; $Id: bs3-cmn-RegCtxSaveEx.asm 60657 2016-04-22 15:57:22Z vboxsync $ ;; @file ; BS3Kit - Bs3RegCtxSaveEx. ; ; ; Copyright (C) 2007-2016 Oracle Corporation ; ; This file is part of VirtualBox Open Source Edition (OSE), as ; available from http://www.virtualbox.org. This file is free software; ; you can redistribute it and/or modify it under the terms of the GNU ; General Public License (GPL) as published by the Free Software ; Foundation, in version 2 as it comes in the "COPYING" file of the ; VirtualBox OSE distribution. VirtualBox OSE is distributed in the ; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. ; ; The contents of this file may alternatively be used under the terms ; of the Common Development and Distribution License Version 1.0 ; (CDDL) only, as it comes in the "COPYING.CDDL" file of the ; VirtualBox OSE distribution, in which case the provisions of the ; CDDL are applicable instead of those of the GPL. ; ; You may elect to license modified versions of this file under the ; terms and conditions of either the GPL or the CDDL or both. ; %include "bs3kit-template-header.mac" ;********************************************************************************************************************************* ;* External Symbols * ;********************************************************************************************************************************* BS3_EXTERN_DATA16 g_bBs3CurrentMode 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 %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 ; ; 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 ; xBP - xCB*1: save space for 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. ; mov ax, [xBP + xCB + cbCurRetAddr + sCB + xCB] %ifdef BS3_STRICT cmp ax, 4096 jb .extra_stack_ok call Bs3Panic .extra_stack_ok: %endif cmp ax, 20h jae .at_least_20h_extra_stack add ax, 20h .at_least_20h_extra_stack: sub sp, ax ; ; 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 .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 .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 [xBP - xCB*1], BS3_MODE_CODE_16 jne .code_32_back_to_v86 call _Bs3SwitchTo16Bit_c32 BS3_SET_BITS TMPL_BITS jmp .return .code_32_back_to_v86: BS3_SET_BITS 32 call _Bs3SwitchTo16BitV86_c32 %else call _Bs3SwitchTo64Bit_c32 %endif BS3_SET_BITS TMPL_BITS jmp .return %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 _Bs3SwitchTo16Bit_c32 BS3_SET_BITS 16 jmp .return %endif BS3_PROC_END_CMN Bs3RegCtxSaveEx