summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm')
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm401
1 files changed, 401 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm
new file mode 100644
index 00000000..017f112a
--- /dev/null
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm
@@ -0,0 +1,401 @@
+; $Id: bs3-c16-TrapRmV86Generic.asm $
+;; @file
+; BS3Kit - Trap, 16-bit assembly handlers for real mode and v8086.
+;
+
+;
+; 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
+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 _Bs3TrapRmV86GenericEntries
+BS3_PROC_BEGIN Bs3TrapRmV86GenericEntries
+%macro Bs3TrapRmV86GenericEntryNoErr 1
+ push ax ; 1 byte: Reserve space for fake error cd. (BP(+2) + 4)
+ push ax ; 1 byte: Save AX (BP(+2) + 2)
+ mov ax, i | 00000h ; 2 bytes: AL = trap/interrupt number; AH=indicate no error code
+ jmp %1 ; 3 bytes: Jump to handler code
+ ALIGNCODE(8)
+%assign i i+1
+%endmacro
+
+%macro Bs3TrapRmV86GenericEntryErrCd 1
+ Bs3TrapRmV86GenericEntryNoErr %1 ; No error code pushed in real mode or V86 mode.
+%endmacro
+
+%assign i 0 ; start counter.
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 0
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 2
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 3
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 4
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 5
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 6
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 7
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; 8
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 9
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; a
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; b
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; c
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; d
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; e
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; f (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 10
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; 11
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 12
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 13
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 14
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 15 (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 16 (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 17 (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 18 (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 19 (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1a (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1b (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1c (reserved)
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1d (reserved)
+ Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; 1e
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1f (reserved)
+%rep 224
+ Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt
+%endrep
+BS3_PROC_END Bs3TrapRmV86GenericEntries
+AssertCompile(Bs3TrapRmV86GenericEntries_EndProc - Bs3TrapRmV86GenericEntries == 8*256)
+
+
+;;
+; Trap or interrupt with error code, faked if necessary.
+;
+; early 386+ stack (movzx ebp, sp):
+; [bp + 000h] ebp
+; [bp + 004h] ax
+; [bp + 006h] errcd [bp'+0] <--- bp at jmp to common code.
+; [bp + 008h] cs [bp'+2]
+; [bp + 00ah] ip [bp'+4]
+; [bp + 00ch] flags [bp'+6]
+; ([bp + 00eh] post-iret sp value) [bp'+8]
+;
+BS3_PROC_BEGIN _bs3TrapRmV86GenericTrapOrInt
+BS3_PROC_BEGIN bs3TrapRmV86GenericTrapOrInt
+CPU 386
+ jmp near bs3TrapRmV86GenericTrapErrCode8086 ; Bs3TrapRmV86Init 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
+
+ ; 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 edx, [bp - 12h]
+ 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.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 edx, eax ; high bits
+ mov dx, [bp + 4]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], edx
+
+ mov [ss:bx + BS3TRAPFRAME.bXcpt], al
+
+ test ah, 0ffh
+ jz .no_error_code
+ mov dx, [bp + 6]
+ mov [ss:bx + BS3TRAPFRAME.uErrCd], dx
+.no_error_code:
+
+ add bp, 6 ; adjust so it points to the word before the iret frame.
+ xor dx, dx
+ jmp bs3TrapRmV86GenericCommon
+BS3_PROC_END bs3TrapRmV86GenericTrapErrCode
+
+;;
+; Trap with error code - 8086/V20/80186/80286 code variant.
+;
+BS3_PROC_BEGIN bs3TrapRmV86GenericTrapErrCode8086
+CPU 8086
+ push bp
+ mov bp, sp
+ push bx ; BP - 2
+ pushf ; BP - 4
+ push ax ; BP - 6
+ cld
+
+ ; Reserve space for the register and trap frame.
+ mov bx, (BS3TRAPFRAME_size + 7) / 8
+ xor ax, ax
+.more_zeroed_space:
+ push ax
+ push ax
+ push ax
+ push ax
+ dec bx
+ jnz .more_zeroed_space
+ mov bx, sp
+
+ 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 dx, [bp + 2]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], dx
+
+ mov ax, [bp - 6]
+ mov [ss:bx + BS3TRAPFRAME.bXcpt], al
+
+ test ah, 0ffh
+ jz .no_error_code
+ mov dx, [bp + 4]
+ mov [ss:bx + BS3TRAPFRAME.uErrCd], dx
+.no_error_code:
+
+ add bp, 4 ; adjust so it points to the word before the iret frame.
+ mov dl, 1
+ jmp bs3TrapRmV86GenericCommon
+BS3_PROC_END bs3TrapRmV86GenericTrapErrCode8086
+
+
+;;
+; Common context saving code and dispatching.
+;
+; @param ss: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.
+; - 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 bs3TrapRmV86GenericCommon
+CPU 8086
+ ;
+ ; 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 8086
+ 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 BS3KIT_GRPNM_DATA16 into DS and ES so we can access globals.
+ ;
+ mov ax, BS3KIT_GRPNM_DATA16
+ mov ds, ax
+ mov es, ax
+
+ ;
+ ; Copy the mode now that we've got a flat DS. We don't need to update
+ ; it as it didn't change.
+ ;
+ mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], al
+
+ ;
+ ; 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
+ mov cx, ss
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx
+ lea cx, [bp + 8]
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx
+ mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 3*2
+
+ ; The VM flag and CPL.
+ test al, BS3_MODE_CODE_V86
+ jz .dont_set_vm
+ or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags + 2], X86_EFL_VM >> 16
+ mov byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], 3
+.dont_set_vm:
+
+
+ ;
+ ; Control registers.
+ ;
+ ; Since we're in real or v8086 here, we cannot save TR and LDTR.
+ ; But get MSW (CR0) first since that's always accessible and we
+ ; need it even on a 386 to check whether we're in v8086 mode or not.
+ ;
+ cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286
+ jb .skip_control_registers_because_80186_or_older
+CPU 286
+ smsw ax
+ mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], ax
+
+ test dx, dx
+ jnz .set_flags
+.save_386_control_registers:
+CPU 386
+ ; 386 control registers are not accessible from virtual 8086 mode.
+ test al, X86_CR0_PE
+ jnz .skip_crX_because_v8086
+ 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
+
+CPU 8086
+.skip_control_registers_because_80186_or_older:
+.skip_crX_because_v8086:
+ or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], \
+ BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4
+.set_flags: ; The double fault code joins us here.
+ or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 | BS3REG_CTX_F_NO_TR_LDTR
+
+ ;
+ ; 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.
+ ;
+ xor ax, ax
+ push ax
+ push ss
+ add di, BS3TRAPFRAME.Ctx
+ push di
+ call Bs3RegCtxRestore
+.panic:
+ hlt
+ jmp .panic
+BS3_PROC_END bs3TrapRmV86GenericCommon
+