summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm')
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm460
1 files changed, 460 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm
new file mode 100644
index 00000000..94203fe3
--- /dev/null
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm
@@ -0,0 +1,460 @@
+; $Id: bs3-cmn-RegCtxSaveEx.asm $
+;; @file
+; BS3Kit - Bs3RegCtxSaveEx.
+;
+
+;
+; 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
+;
+
+%include "bs3kit-template-header.mac"
+
+
+
+;*********************************************************************************************************************************
+;* External Symbols *
+;*********************************************************************************************************************************
+BS3_EXTERN_DATA16 g_bBs3CurrentMode
+%if ARCH_BITS != 64
+BS3_EXTERN_DATA16 g_uBs3CpuDetected
+%endif
+
+TMPL_BEGIN_TEXT
+BS3_EXTERN_CMN Bs3Panic
+BS3_EXTERN_CMN Bs3RegCtxSave
+BS3_EXTERN_CMN Bs3SwitchTo16Bit
+%if TMPL_BITS != 64
+BS3_EXTERN_CMN Bs3SwitchTo16BitV86
+%endif
+%if TMPL_BITS != 32
+BS3_EXTERN_CMN Bs3SwitchTo32Bit
+%endif
+%if TMPL_BITS != 64
+BS3_EXTERN_CMN Bs3SwitchTo64Bit
+%endif
+%if TMPL_BITS == 16
+BS3_EXTERN_CMN Bs3SelRealModeDataToProtFar16
+BS3_EXTERN_CMN Bs3SelProtFar16DataToRealMode
+BS3_EXTERN_CMN Bs3SelRealModeDataToFlat
+BS3_EXTERN_CMN Bs3SelProtFar16DataToFlat
+%else
+BS3_EXTERN_CMN Bs3SelFlatDataToProtFar16
+%endif
+%if TMPL_BITS == 32
+BS3_EXTERN_CMN Bs3SelFlatDataToRealMode
+%endif
+
+BS3_BEGIN_TEXT16
+%if TMPL_BITS != 16
+extern _Bs3RegCtxSave_c16
+extern _Bs3SwitchTo%[TMPL_BITS]Bit_c16
+%endif
+
+BS3_BEGIN_TEXT32
+%if TMPL_BITS != 32
+extern _Bs3RegCtxSave_c32
+extern _Bs3SwitchTo%[TMPL_BITS]Bit_c32
+%endif
+%if TMPL_BITS == 16
+extern _Bs3SwitchTo16BitV86_c32
+%endif
+
+BS3_BEGIN_TEXT64
+%if TMPL_BITS != 64
+extern _Bs3RegCtxSave_c64
+extern _Bs3SwitchTo%[TMPL_BITS]Bit_c64
+%endif
+
+TMPL_BEGIN_TEXT
+
+
+
+;;
+; Saves the current register context.
+;
+; @param pRegCtx
+; @param bBitMode (8)
+; @param cbExtraStack (16)
+; @uses xAX, xDX, xCX
+;
+BS3_PROC_BEGIN_CMN Bs3RegCtxSaveEx, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h.
+TONLY16 CPU 8086
+ BS3_CALL_CONV_PROLOG 3
+ push xBP
+ mov xBP, xSP
+%if ARCH_BITS == 64
+ push rcx ; Save pRegCtx
+%endif
+
+ ;
+ ; Get the CPU bitcount part of the current mode.
+ ;
+ mov dl, [BS3_DATA16_WRT(g_bBs3CurrentMode)]
+ and dl, BS3_MODE_CODE_MASK
+%if TMPL_BITS == 16
+ push dx ; bp - 2: previous CPU mode (16-bit)
+%endif
+
+ ;
+ ; Reserve extra stack space. Make sure we've got 20h here in case we
+ ; are saving a 64-bit context.
+ ;
+TONLY16 mov ax, [xBP + xCB + cbCurRetAddr + sCB + xCB]
+TNOT16 movzx eax, word [xBP + xCB + cbCurRetAddr + sCB + xCB]
+%ifdef BS3_STRICT
+ cmp xAX, 4096
+ jb .extra_stack_ok
+ call Bs3Panic
+.extra_stack_ok:
+%endif
+ cmp xAX, 20h
+ jae .at_least_20h_extra_stack
+ add xAX, 20h
+.at_least_20h_extra_stack:
+ sub xSP, xAX
+
+ ;
+ ; Are we just saving the mode we're already in?
+ ;
+ mov al, [xBP + xCB + cbCurRetAddr + sCB]
+ and al, BS3_MODE_CODE_MASK
+ cmp dl, al
+ jne .not_the_same_mode
+
+%if TMPL_BITS == 16
+ push word [xBP + xCB + cbCurRetAddr + 2]
+ push word [xBP + xCB + cbCurRetAddr]
+%elif TMPL_BITS == 32
+ push dword [xBP + xCB + cbCurRetAddr]
+%endif
+ call Bs3RegCtxSave ; 64-bit: rcx is untouched thus far.
+
+
+ ;
+ ; Return - no need to pop xAX and xDX as the last two
+ ; operations preserves all registers.
+ ;
+.return:
+ mov xSP, xBP
+ pop xBP
+ BS3_CALL_CONV_EPILOG 3
+ BS3_HYBRID_RET
+
+ ;
+ ; Turns out we have to do switch to a different bitcount before saving.
+ ;
+.not_the_same_mode:
+ cmp al, BS3_MODE_CODE_16
+ je .code_16
+
+TONLY16 CPU 386
+%if TMPL_BITS != 32
+ cmp al, BS3_MODE_CODE_32
+ je .code_32
+%endif
+%if TMPL_BITS != 64
+ cmp al, BS3_MODE_CODE_V86
+ je .code_v86
+ cmp al, BS3_MODE_CODE_64
+ jne .bad_input_mode
+ jmp .code_64
+%endif
+
+ ; Bad input (al=input, dl=current).
+.bad_input_mode:
+ call Bs3Panic
+
+
+ ;
+ ; Save a 16-bit context.
+ ;
+ ; Convert pRegCtx to 16:16 protected mode and make sure we're in the
+ ; 16-bit code segment.
+ ;
+.code_16:
+%if TMPL_BITS == 16
+ %ifdef BS3_STRICT
+ cmp dl, BS3_MODE_CODE_V86
+ jne .bad_input_mode
+ %endif
+ push word [xBP + xCB + cbCurRetAddr + 2]
+ push word [xBP + xCB + cbCurRetAddr]
+ call Bs3SelRealModeDataToProtFar16
+ add sp, 4h
+ push dx ; Parameter #0 for _Bs3RegCtxSave_c16
+ push ax
+%else
+ %if TMPL_BITS == 32
+ push dword [xBP + xCB + cbCurRetAddr]
+ %endif
+ call Bs3SelFlatDataToProtFar16 ; 64-bit: BS3_CALL not needed, ecx not touched thus far.
+ mov [xSP], eax ; Parameter #0 for _Bs3RegCtxSave_c16
+ jmp .code_16_safe_segment
+ BS3_BEGIN_TEXT16
+ BS3_SET_BITS TMPL_BITS
+.code_16_safe_segment:
+%endif
+ call Bs3SwitchTo16Bit
+ BS3_SET_BITS 16
+
+ call _Bs3RegCtxSave_c16
+
+%if TMPL_BITS == 16
+ call _Bs3SwitchTo16BitV86_c16
+%else
+ call _Bs3SwitchTo%[TMPL_BITS]Bit_c16
+%endif
+ BS3_SET_BITS TMPL_BITS
+ jmp .supplement_and_return
+ TMPL_BEGIN_TEXT
+
+TONLY16 CPU 386
+
+
+%if TMPL_BITS != 64
+ ;
+ ; Save a v8086 context.
+ ;
+.code_v86:
+ %if TMPL_BITS == 16
+ %ifdef BS3_STRICT
+ cmp dl, BS3_MODE_CODE_16
+ jne .bad_input_mode
+ %endif
+ push word [xBP + xCB + cbCurRetAddr + 2]
+ push word [xBP + xCB + cbCurRetAddr]
+ call Bs3SelProtFar16DataToRealMode
+ add sp, 4h
+ push dx ; Parameter #0 for _Bs3RegCtxSave_c16
+ push ax
+ %else
+ push dword [xBP + xCB + cbCurRetAddr]
+ call Bs3SelFlatDataToRealMode
+ mov [xSP], eax ; Parameter #0 for _Bs3RegCtxSave_c16
+ jmp .code_v86_safe_segment
+ BS3_BEGIN_TEXT16
+ BS3_SET_BITS TMPL_BITS
+.code_v86_safe_segment:
+ %endif
+ call Bs3SwitchTo16BitV86
+ BS3_SET_BITS 16
+
+ call _Bs3RegCtxSave_c16
+
+ call _Bs3SwitchTo%[TMPL_BITS]Bit_c16
+ BS3_SET_BITS TMPL_BITS
+ jmp .supplement_and_return
+TMPL_BEGIN_TEXT
+%endif
+
+
+%if TMPL_BITS != 32
+ ;
+ ; Save a 32-bit context.
+ ;
+.code_32:
+ %if TMPL_BITS == 16
+ push word [xBP + xCB + cbCurRetAddr + 2]
+ push word [xBP + xCB + cbCurRetAddr]
+ test dl, BS3_MODE_CODE_V86
+ jnz .code_32_from_v86
+ call Bs3SelProtFar16DataToFlat
+ jmp .code_32_flat_ptr
+.code_32_from_v86:
+ call Bs3SelRealModeDataToFlat
+.code_32_flat_ptr:
+ add sp, 4h
+ push dx ; Parameter #0 for _Bs3RegCtxSave_c32
+ push ax
+ %else
+ mov [rsp], ecx ; Parameter #0 for _Bs3RegCtxSave_c16
+ %endif
+ call Bs3SwitchTo32Bit
+ BS3_SET_BITS 32
+
+ call _Bs3RegCtxSave_c32
+
+ %if TMPL_BITS == 16
+ cmp byte [bp - 2], BS3_MODE_CODE_V86
+ je .code_32_back_to_v86
+ call _Bs3SwitchTo16Bit_c32
+ BS3_SET_BITS TMPL_BITS
+ jmp .supplement_and_return
+.code_32_back_to_v86:
+ BS3_SET_BITS 32
+ call _Bs3SwitchTo16BitV86_c32
+ BS3_SET_BITS TMPL_BITS
+ jmp .return
+ %else
+ call _Bs3SwitchTo64Bit_c32
+ BS3_SET_BITS TMPL_BITS
+ jmp .supplement_and_return
+ %endif
+%endif
+
+
+%if TMPL_BITS != 64
+ ;
+ ; Save a 64-bit context.
+ ;
+ CPU x86-64
+.code_64:
+ %if TMPL_BITS == 16
+ %ifdef BS3_STRICT
+ cmp dl, BS3_MODE_CODE_16
+ jne .bad_input_mode
+ %endif
+ push word [xBP + xCB + cbCurRetAddr + 2]
+ push word [xBP + xCB + cbCurRetAddr]
+ call Bs3SelProtFar16DataToFlat
+ add sp, 4h
+ mov cx, dx ; Parameter #0 for _Bs3RegCtxSave_c64
+ shl ecx, 16
+ mov cx, ax
+ %else
+ mov ecx, [xBP + xCB + cbCurRetAddr] ; Parameter #0 for _Bs3RegCtxSave_c64
+ %endif
+ call Bs3SwitchTo64Bit ; (preserves all 32-bit GPRs)
+ BS3_SET_BITS 64
+
+ call _Bs3RegCtxSave_c64 ; No BS3_CALL as rcx is already ready.
+
+ call _Bs3SwitchTo%[TMPL_BITS]Bit_c64
+ BS3_SET_BITS TMPL_BITS
+ jmp .return
+%endif
+
+
+ ;
+ ; Supplement the state out of the current context and then return.
+ ;
+.supplement_and_return:
+%if ARCH_BITS == 16
+ CPU 8086
+ ; Skip 286 and older. Also make 101% sure we not in real mode or v8086 mode.
+ cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386
+ jb .return ; Just skip if 286 or older.
+ test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86
+ jnz .return
+ cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM
+ jne .return ; paranoia
+ CPU 386
+%endif
+
+ ; Load the context pointer into a suitable register.
+%if ARCH_BITS == 64
+ %define pRegCtx rcx
+ mov rcx, [xBP - xCB]
+%elif ARCH_BITS == 32
+ %define pRegCtx ecx
+ mov ecx, [xBP + xCB + cbCurRetAddr]
+%else
+ %define pRegCtx es:bx
+ push es
+ push bx
+ les bx, [xBP + xCB + cbCurRetAddr]
+%endif
+%if ARCH_BITS == 64
+ ; If we're in 64-bit mode we can capture and restore the high bits.
+ test byte [pRegCtx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64
+ jz .supplemented_64bit_registers
+ mov [pRegCtx + BS3REGCTX.r8], r8
+ mov [pRegCtx + BS3REGCTX.r9], r9
+ mov [pRegCtx + BS3REGCTX.r10], r10
+ mov [pRegCtx + BS3REGCTX.r11], r11
+ mov [pRegCtx + BS3REGCTX.r12], r12
+ mov [pRegCtx + BS3REGCTX.r13], r13
+ mov [pRegCtx + BS3REGCTX.r14], r14
+ mov [pRegCtx + BS3REGCTX.r15], r15
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rax + 4], eax
+ mov rax, rbx
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rbx + 4], eax
+ mov rax, rcx
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rcx + 4], eax
+ mov rax, rdx
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rdx + 4], eax
+ mov rax, rsp
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rsp + 4], eax
+ mov rax, rbp
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rbp + 4], eax
+ mov rax, rsi
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rsi + 4], eax
+ mov rax, rdi
+ shr rax, 32
+ mov [pRegCtx + BS3REGCTX.rdi + 4], eax
+ and byte [pRegCtx + BS3REGCTX.fbFlags], ~BS3REG_CTX_F_NO_AMD64
+.supplemented_64bit_registers:
+%endif
+ ; The rest requires ring-0 (at least during restore).
+ mov ax, ss
+ test ax, 3
+ jnz .done_supplementing
+
+ ; Do control registers.
+ test byte [pRegCtx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR4
+ jz .supplemented_control_registers
+ mov sAX, cr0
+ mov [pRegCtx + BS3REGCTX.cr0], sAX
+ mov sAX, cr2
+ mov [pRegCtx + BS3REGCTX.cr2], sAX
+ mov sAX, cr3
+ mov [pRegCtx + BS3REGCTX.cr3], sAX
+ and byte [pRegCtx + BS3REGCTX.fbFlags], ~(BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR0_IS_MSW)
+
+%if ARCH_BITS != 64
+ test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8)
+ jz .supplemented_control_registers
+%endif
+ mov sAX, cr4
+ mov [pRegCtx + BS3REGCTX.cr4], sAX
+ and byte [pRegCtx + BS3REGCTX.fbFlags], ~BS3REG_CTX_F_NO_CR4
+.supplemented_control_registers:
+
+ ; Supply tr and ldtr if necessary
+ test byte [pRegCtx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_TR_LDTR
+ jz .done_supplementing
+ str [pRegCtx + BS3REGCTX.tr]
+ sldt [pRegCtx + BS3REGCTX.ldtr]
+ and byte [pRegCtx + BS3REGCTX.fbFlags], ~BS3REG_CTX_F_NO_TR_LDTR
+
+.done_supplementing:
+TONLY16 pop bx
+TONLY16 pop es
+ jmp .return
+%undef pRegCtx
+BS3_PROC_END_CMN Bs3RegCtxSaveEx
+