summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm')
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm720
1 files changed, 720 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
new file mode 100644
index 00000000..3db838a2
--- /dev/null
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm
@@ -0,0 +1,720 @@
+; $Id: bs3-c16-Trap16Generic.asm $
+;; @file
+; BS3Kit - Trap, 16-bit assembly handlers.
+;
+
+;
+; 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
+;
+
+;*********************************************************************************************************************************
+;* Header Files *
+;*********************************************************************************************************************************
+%include "bs3kit-template-header.mac"
+
+%ifndef TMPL_16BIT
+ %error "16-bit only template"
+%endif
+
+
+;*********************************************************************************************************************************
+;* External Symbols *
+;*********************************************************************************************************************************
+BS3_EXTERN_DATA16 g_bBs3CurrentMode
+BS3_EXTERN_DATA16 g_uBs3TrapEipHint
+BS3_EXTERN_DATA16 g_uBs3CpuDetected
+BS3_EXTERN_DATA16 g_apfnBs3TrapHandlers_c16
+BS3_EXTERN_SYSTEM16 Bs3Gdt
+TMPL_BEGIN_TEXT
+BS3_EXTERN_CMN Bs3TrapDefaultHandler
+BS3_EXTERN_CMN Bs3RegCtxRestore
+TMPL_BEGIN_TEXT
+
+
+;;
+; Generic entry points for IDT handlers, 8 byte spacing.
+;
+BS3_PROC_BEGIN _Bs3Trap16GenericEntries
+BS3_PROC_BEGIN Bs3Trap16GenericEntries
+%macro Bs3Trap16GenericEntryNoErr 1
+ push byte 0 ; 2 byte: fake error code
+ db 06ah, i ; 2 byte: push imm8 - note that this is a signextended value.
+ jmp %1 ; 3 byte
+ ALIGNCODE(8)
+%assign i i+1
+%endmacro
+
+%macro Bs3Trap16GenericEntryErrCd 1
+ db 06ah, i ; 2 byte: push imm8 - note that this is a signextended value.
+ jmp %1 ; 3 byte
+ ALIGNCODE(8)
+%assign i i+1
+%endmacro
+
+%assign i 0 ; start counter.
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 0
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 2
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 3
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 4
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 5
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 6
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 7
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; 8
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 9
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; a
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; b
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; c
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; d
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; e
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; f (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 10
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; 11
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 12
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 13
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 14
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 15 (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 16 (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 17 (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 18 (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 19 (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1a (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1b (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1c (reserved)
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1d (reserved)
+ Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; 1e
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1f (reserved)
+%rep 224
+ Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt
+%endrep
+BS3_PROC_END Bs3Trap16GenericEntries
+AssertCompile(Bs3Trap16GenericEntries_EndProc - Bs3Trap16GenericEntries == 8*256)
+
+
+;;
+; Trap or interrupt with error code, faked if necessary.
+;
+; Note! This code is going to "misbehave" if the high word of ESP is not cleared.
+;
+BS3_PROC_BEGIN _bs3Trap16GenericTrapOrInt
+BS3_PROC_BEGIN bs3Trap16GenericTrapOrInt
+CPU 386
+ jmp near bs3Trap16GenericTrapErrCode80286 ; Bs3Trap16Init adjusts this on 80386+
+ push ebp
+ movzx ebp, sp
+ push ebx ; BP - 04h
+ pushfd ; BP - 08h
+ cld
+ push edx ; BP - 0ch
+ push ss ; BP - 0eh
+ push esp ; BP - 12h
+
+ ;
+ ; We may be comming from 32-bit code where SS is flat and ESP has a non-
+ ; zero high word. We need to thunk it for C code to work correctly with
+ ; [BP+xx] and [SS:BX+xx] style addressing that leaves out the high word.
+ ;
+ ; Note! Require ring-0 handler for non-standard stacks (SS.DPL must equal CPL).
+ ;
+ mov bx, ss
+ lar ebx, bx
+ test ebx, X86LAR_F_D
+ jz .stack_fine
+ test esp, 0ffff0000h
+ jnz .stack_thunk
+.stack_load_r0_ss16:
+ mov bx, ss
+ and bl, 3
+ AssertCompile(BS3_SEL_RING_SHIFT == 8)
+ mov bh, bl
+ add bx, BS3_SEL_R0_SS16
+ jmp .stack_load_bx_into_ss
+.stack_thunk:
+ mov ebx, esp
+ shr ebx, 16
+ shl ebx, X86_SEL_SHIFT
+ add ebx, BS3_SEL_TILED_R0
+ cmp ebx, BS3_SEL_TILED_R0_LAST
+ ja .stack_esp_out_of_bounds
+.stack_load_bx_into_ss:
+ mov ss, bx
+.stack_fine:
+ movzx esp, sp
+
+ ; Reserve space for the register and trap frame.
+ mov bx, (BS3TRAPFRAME_size + 7) / 8
+.more_zeroed_space:
+ push 0
+ push 0
+ push 0
+ push 0
+ dec bx
+ jnz .more_zeroed_space
+ movzx ebx, sp
+
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], eax
+ mov edx, [bp - 12h] ; This isn't quite right for wrap arounds, but close enough for now
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], edx ; high bits
+ mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], edx ; high bits
+ mov dx, [bp - 0eh]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], dx
+ mov [ss:bx + BS3TRAPFRAME.uHandlerSs], dx
+ mov edx, [bp - 0ch]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], edx
+ mov edx, [bp - 8]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], edx ; high bits
+ mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], edx
+ mov edx, [bp - 4]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], edx
+ mov edx, [bp]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], edx
+
+ mov dl, [bp + 4]
+ mov [ss:bx + BS3TRAPFRAME.bXcpt], dl
+
+ mov dx, [bp + 6]
+;; @todo Do voodoo checks for 'int xx' or misguided hardware interrupts.
+ mov [ss:bx + BS3TRAPFRAME.uErrCd], dx
+
+ add bp, 6 ; adjust so it points to the word before the iret frame.
+ xor dx, dx
+ jmp bs3Trap16GenericCommon
+
+.stack_esp_out_of_bounds:
+%ifdef BS3_STRICT
+ int3
+%endif
+ jmp .stack_esp_out_of_bounds
+BS3_PROC_END bs3Trap16GenericTrapErrCode
+
+;;
+; Trap with error code - 80286 code variant.
+;
+BS3_PROC_BEGIN bs3Trap16GenericTrapErrCode80286
+CPU 286
+ push bp
+ mov bp, sp
+ push bx
+ pushf
+ cld
+
+ ; Reserve space for the register and trap frame.
+ mov bx, (BS3TRAPFRAME_size + 7) / 8
+.more_zeroed_space:
+ push 0
+ push 0
+ push 0
+ push 0
+ dec bx
+ jnz .more_zeroed_space
+ mov bx, sp
+
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], ax
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], ss
+ mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], dx
+ mov dx, [bp - 4]
+ mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], dx
+ mov dx, [bp - 2]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], dx
+ mov dx, [bp]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], dx
+
+ mov dl, [bp + 2]
+ mov [ss:bx + BS3TRAPFRAME.bXcpt], dl
+
+ mov dx, [bp + 4]
+;; @todo Do voodoo checks for 'int xx' or misguided hardware interrupts.
+ mov [ss:bx + BS3TRAPFRAME.uErrCd], dx
+
+ add bp, 4 ; adjust so it points to the word before the iret frame.
+ mov dl, 1
+ jmp bs3Trap16GenericCommon
+BS3_PROC_END bs3Trap16GenericTrapErrCode80286
+
+
+;;
+; Common context saving code and dispatching.
+;
+; @param bx Pointer to the trap frame, zero filled. The following members
+; have been filled in by the previous code:
+; - bXcpt
+; - uErrCd
+; - fHandlerRFL
+; - Ctx.eax
+; - Ctx.edx
+; - Ctx.ebx
+; - Ctx.ebp
+; - Ctx.rflags - high bits only.
+; - Ctx.esp - high bits only.
+; - Ctx.ss - for same cpl frames
+; - All other bytes are zeroed.
+;
+; @param bp Pointer to the word before the iret frame, i.e. where bp
+; would be saved if this was a normal near call.
+; @param dx One (1) if 286, zero (0) if 386+.
+;
+BS3_PROC_BEGIN bs3Trap16GenericCommon
+CPU 286
+ ;
+ ; Fake EBP frame.
+ ;
+ mov ax, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp]
+ mov [bp], ax
+
+ ;
+ ; Save the remaining GPRs and segment registers.
+ ;
+ test dx, dx
+ jnz .save_word_grps
+CPU 386
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], edi
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], esi
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs
+ jmp .save_segment_registers
+.save_word_grps:
+CPU 286
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], cx
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], di
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], si
+.save_segment_registers:
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], ds
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], es
+ mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs
+
+ ;
+ ; Load 16-bit data selector for the DPL we're executing at into DS and ES.
+ ;
+ mov ax, ss
+ and ax, 3
+ mov cx, ax
+ shl ax, BS3_SEL_RING_SHIFT
+ or ax, cx
+ add ax, BS3_SEL_R0_DS16
+ mov ds, ax
+ mov es, ax
+
+ ;
+ ; Copy and update the mode now that we've got a flat DS.
+ ;
+ mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], al
+ mov cl, al
+ and cl, ~BS3_MODE_CODE_MASK
+ or cl, BS3_MODE_CODE_16
+ mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], cl
+
+ ;
+ ; Copy iret info.
+ ;
+ lea cx, [bp + 2]
+ mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], cx
+ mov cx, [bp + 2]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], cx
+ mov cx, [bp + 6]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], cx
+ mov cx, [bp + 4]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx
+
+ test al, BS3_MODE_CODE_V86
+ jnz .iret_frame_v8086
+
+ mov ax, ss
+ and al, 3
+ and cl, 3
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl
+ cmp cl, al
+ je .iret_frame_same_cpl
+
+.ret_frame_different_cpl:
+ mov cx, [bp + 10]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx
+ mov cx, [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx
+ mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 5*2
+ test dx, dx
+ jnz .iret_frame_done
+ jmp .iret_frame_seed_high_eip_word
+
+.iret_frame_same_cpl: ; (ss and high bits was saved by CPU specific part)
+ lea cx, [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx
+ mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 3*2
+ test dx, dx
+ jnz .iret_frame_done
+ jmp .iret_frame_seed_high_eip_word
+
+.iret_frame_v8086:
+CPU 386
+ or dword [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], X86_EFL_VM
+ mov byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], 3
+ or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], BS3_MODE_CODE_V86 ; paranoia ^ 2
+%if 0 ;; @todo testcase: high ESP word from V86 mode, 16-bit TSS.
+ movzx ecx, word [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], ecx
+%else
+ mov cx, word [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx
+%endif
+ mov cx, [bp + 10]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx
+ mov cx, [bp + 12]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], cx
+ mov cx, [bp + 14]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], cx
+ mov cx, [bp + 16]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], cx
+ mov cx, [bp + 18]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], cx
+ mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 9*2
+ jmp .iret_frame_done
+
+ ;
+ ; For 386 we do special tricks to supply the high word of EIP when
+ ; arriving here from 32-bit code. (ESP was seeded earlier.)
+ ;
+.iret_frame_seed_high_eip_word:
+ lar eax, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs]
+ jnz .iret_frame_done
+ test eax, X86LAR_F_D
+ jz .iret_frame_done
+ mov ax, [g_uBs3TrapEipHint+2]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip + 2], ax
+
+.iret_frame_done:
+ ;
+ ; Control registers.
+ ;
+ str [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.tr]
+ sldt [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr]
+ test dx, dx
+ jnz .save_286_control_registers
+.save_386_control_registers:
+CPU 386
+ mov ax, ss
+ test al, 3
+ jnz .skip_crX_because_cpl_not_0
+ mov eax, cr0
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], eax
+ mov eax, cr2
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], eax
+ mov eax, cr3
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], eax
+
+ test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) ; CR4 first appeared in later 486es.
+ jz .skip_cr4_because_not_there
+ mov eax, cr4
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], eax
+ jmp .set_flags
+
+.skip_cr4_because_not_there:
+ mov byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4
+ jmp .set_flags
+
+.skip_crX_because_cpl_not_0:
+ or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], \
+ BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4 | BS3REG_CTX_F_NO_CR0_IS_MSW
+
+CPU 286
+.save_286_control_registers:
+ smsw [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0]
+
+.set_flags: ; The double fault code joins us here.
+ or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64
+
+ ;
+ ; Dispatch it to C code.
+ ;
+.dispatch_to_handler:
+ mov di, bx
+ mov bl, byte [ss:bx + BS3TRAPFRAME.bXcpt]
+ mov bh, 0
+ shl bx, 1
+ mov bx, [bx + BS3_DATA16_WRT(_g_apfnBs3TrapHandlers_c16)]
+ or bx, bx
+ jnz .call_handler
+ mov bx, Bs3TrapDefaultHandler
+.call_handler:
+ push ss
+ push di
+ call bx
+
+ ;
+ ; Resume execution using trap frame.
+ ;
+ push 0
+ push ss
+ add di, BS3TRAPFRAME.Ctx
+ push di
+ call Bs3RegCtxRestore
+.panic:
+ hlt
+ jmp .panic
+BS3_PROC_END bs3Trap16GenericCommon
+
+
+;;
+; Helper.
+;
+; @retruns Flat address in es:di.
+; @param di
+; @uses eax
+;
+bs3Trap16TssInDiToFar1616InEsDi:
+CPU 286
+ push ax
+
+ ; ASSUME Bs3Gdt is being used.
+ push BS3_SEL_SYSTEM16
+ pop es
+ and di, 0fff8h
+ add di, Bs3Gdt wrt BS3SYSTEM16
+
+ ; Load the TSS base into ax:di (di is low, ax high)
+ mov al, [es:di + (X86DESCGENERIC_BIT_OFF_BASE_HIGH1 / 8)]
+ mov ah, [es:di + (X86DESCGENERIC_BIT_OFF_BASE_HIGH2 / 8)]
+ mov di, [es:di + (X86DESCGENERIC_BIT_OFF_BASE_LOW / 8)]
+
+ ; Convert ax to tiled selector, if not within the tiling area we read
+ ; random BS3SYSTEM16 bits as that's preferable to #GP'ing.
+ shl ax, X86_SEL_SHIFT
+ cmp ax, BS3_SEL_TILED_LAST - BS3_SEL_TILED
+%ifdef BS3_STRICT
+ jbe .tiled
+ int3
+%endif
+ ja .return ; don't crash again.
+.tiled:
+ add ax, BS3_SEL_TILED
+ mov es, ax
+.return:
+ pop ax
+ ret
+
+
+;;
+; Double fault handler.
+;
+; We don't have to load any selectors or clear anything in EFLAGS because the
+; TSS specified sane values which got loaded during the task switch.
+;
+; @param dx Zero (0) for indicating 386+ to the common code.
+;
+BS3_PROC_BEGIN _Bs3Trap16DoubleFaultHandler80386
+BS3_PROC_BEGIN Bs3Trap16DoubleFaultHandler80386
+CPU 386
+ push 0 ; We'll copy the rip from the other TSS here later to create a more sensible call chain.
+ push ebp
+ mov bp, sp
+ pushfd ; Handler flags.
+
+ ; Reserve space for the register and trap frame.
+ mov bx, (BS3TRAPFRAME_size + 15) / 16
+.more_zeroed_space:
+ push dword 0
+ push dword 0
+ push dword 0
+ push dword 0
+ dec bx
+ jz .more_zeroed_space
+ mov bx, sp
+
+ ;
+ ; Fill in the high GRP register words before we mess them up.
+ ;
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], eax
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], ebx
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], edx
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], esi
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], edi
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], ebp
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], esp
+
+ ;
+ ; FS and GS are not part of the 16-bit TSS because they are 386+ specfic.
+ ;
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs
+
+ ;
+ ; Fill in the non-context trap frame bits.
+ ;
+ mov ecx, [bp - 4]
+ mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], ecx
+ mov byte [ss:bx + BS3TRAPFRAME.bXcpt], X86_XCPT_DF
+ mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs
+ mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss
+ mov ecx, esp
+ lea cx, [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], ecx
+ mov cx, [bp + 6]
+ mov [ss:bx + BS3TRAPFRAME.uErrCd], cx
+
+ ;
+ ; Copy 80386+ control registers.
+ ;
+ mov ecx, cr0
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], ecx
+ mov ecx, cr2
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], ecx
+ mov ecx, cr3
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], ecx
+
+ test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) ; CR4 first appeared in later 486es.
+ jz .skip_cr4_because_not_there
+ mov ecx, cr4
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], ecx
+ jmp .common
+
+.skip_cr4_because_not_there:
+ mov byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4
+
+ ;
+ ; Copy the register state from the previous task segment.
+ ; The 80286 code with join us here.
+ ;
+.common:
+CPU 286
+ ; Find our TSS.
+ str di
+ call bs3Trap16TssInDiToFar1616InEsDi
+
+ ; Find the previous TSS.
+ mov di, [es:di + X86TSS32.selPrev]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.tr], ax
+ call bs3Trap16TssInDiToFar1616InEsDi
+
+ ; Do the copying.
+ mov cx, [es:di + X86TSS16.ax]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], cx
+ mov cx, [es:di + X86TSS16.cx]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], cx
+ mov cx, [es:di + X86TSS16.dx]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], cx
+ mov cx, [es:di + X86TSS16.bx]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], cx
+ mov cx, [es:di + X86TSS16.sp]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx
+ mov cx, [es:di + X86TSS16.bp]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], cx
+ mov [bp], cx ; For better call stacks.
+ mov cx, [es:di + X86TSS16.si]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], cx
+ mov cx, [es:di + X86TSS16.di]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], cx
+ mov cx, [es:di + X86TSS16.si]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], cx
+ mov cx, [es:di + X86TSS16.flags]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], cx
+ mov cx, [es:di + X86TSS16.ip]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], cx
+ mov [bp + 2], cx ; For better call stacks.
+ mov cx, [es:di + X86TSS16.cs]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx
+ mov cx, [es:di + X86TSS16.ds]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], cx
+ mov cx, [es:di + X86TSS16.es]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], cx
+ mov cx, [es:di + X86TSS16.ss]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx
+ mov cx, [es:di + X86TSS16.selLdt] ; Note! This isn't necessarily the ldtr at the time of the fault.
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr], cx
+
+ ;
+ ; Set CPL; copy and update mode.
+ ;
+ mov cl, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss]
+ and cl, 3
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl
+
+ mov cl, [BS3_DATA16_WRT(g_bBs3CurrentMode)]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], cl
+ and cl, ~BS3_MODE_CODE_MASK
+ or cl, BS3_MODE_CODE_16
+ mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], cl
+
+ ;
+ ; Join code paths with the generic handler code.
+ ;
+ jmp bs3Trap16GenericCommon.set_flags
+BS3_PROC_END Bs3Trap16DoubleFaultHandler
+
+
+;;
+; Double fault handler.
+;
+; We don't have to load any selectors or clear anything in EFLAGS because the
+; TSS specified sane values which got loaded during the task switch.
+;
+; @param dx One (1) for indicating 386+ to the common code.
+;
+BS3_PROC_BEGIN _Bs3Trap16DoubleFaultHandler80286
+BS3_PROC_BEGIN Bs3Trap16DoubleFaultHandler80286
+CPU 286
+ push 0 ; We'll copy the rip from the other TSS here later to create a more sensible call chain.
+ push bp
+ mov bp, sp
+ pushf ; Handler flags.
+
+ ; Reserve space for the register and trap frame.
+ mov bx, (BS3TRAPFRAME_size + 7) / 8
+.more_zeroed_space:
+ push 0
+ push 0
+ push 0
+ push 0
+ dec bx
+ jz .more_zeroed_space
+ mov bx, sp
+
+ ;
+ ; Fill in the non-context trap frame bits.
+ ;
+ mov cx, [bp - 2]
+ mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], cx
+ mov byte [ss:bx + BS3TRAPFRAME.bXcpt], X86_XCPT_DF
+ mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs
+ mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss
+ lea cx, [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], cx
+ mov cx, [bp + 6]
+ mov [ss:bx + BS3TRAPFRAME.uErrCd], cx
+
+ ;
+ ; Copy 80286 specific control register.
+ ;
+ smsw [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0]
+
+ jmp Bs3Trap16DoubleFaultHandler80386.common
+BS3_PROC_END Bs3Trap16DoubleFaultHandler80286
+