diff options
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm')
-rw-r--r-- | src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm | 891 |
1 files changed, 891 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm new file mode 100644 index 00000000..80cb56b8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm @@ -0,0 +1,891 @@ +; $Id: bs3-mode-TrapSystemCallHandler.asm $ +;; @file +; BS3Kit - System call trap handler. +; + +; +; Copyright (C) 2007-2022 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" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_uBs3TrapEipHint +%endif +TMPL_BEGIN_TEXT + +BS3_EXTERN_CMN Bs3SelProtFar32ToFlat32 +BS3_EXTERN_CMN Bs3RegCtxConvertToRingX +BS3_EXTERN_CMN Bs3RegCtxRestore +BS3_EXTERN_CMN Bs3Panic + +BS3_BEGIN_TEXT16 +extern Bs3PrintStrN_c16_CX_Bytes_At_DS_SI +TMPL_BEGIN_TEXT + + +;; +; System call handler. +; +; This is an assembly trap handler that is called in response to a system call +; request from 'user' code. The only fixed parameter is [ER]AX which contains +; the system call number. Other registers are assigned on a per system call +; basis, ditto for which registers are preserved and which are used to return +; stuff. Generally, though, we preserve all registers not used as return +; values or otherwise implicitly transformed by the call. +; +; Note! The 16-bit versions of this code must be careful with using extended +; registers as we wish this code to work on real 80286 (maybe even 8086) +; CPUs too! +; +BS3_PROC_BEGIN_MODE Bs3TrapSystemCallHandler, BS3_PBC_NEAR ; Near because we'll probably only ever need this from CGROUP16. + ; + ; This prologue is kind of complicated because of 80286 and older CPUs + ; as well as different requirements for 64-bit and the other modes. + ; +%define VAR_CALLER_BP [xBP] +%if TMPL_BITS != 64 + %define VAR_CALLER_DS [xBP - xCB] +%endif +%define VAR_CALLER_BX [xBP - sCB*1 - xCB] ; Note! the upper word is not clean on pre-386 (16-bit mode). +%define VAR_CALLER_AX [xBP - sCB*2 - xCB] +%define VAR_CALLER_CX [xBP - sCB*3 - xCB] +%define VAR_CALLER_DX [xBP - sCB*4 - xCB] +%define VAR_CALLER_SI [xBP - sCB*5 - xCB] +%define VAR_CALLER_SI_HI [xBP - sCB*5 - xCB + 2] +%define VAR_CALLER_DI [xBP - sCB*6 - xCB] +%define VAR_CALLER_DI_HI [xBP - sCB*6 - xCB + 2] +%if TMPL_BITS == 16 + %define VAR_CALLER_EBP [xBP - sCB*7 - xCB] + %define VAR_CALLER_ESP [xBP - sCB*8 - xCB] + %define VAR_CALLER_EFLAGS [xBP - sCB*9 - xCB] + %define VAR_CALLER_MODE [xBP - sCB*9 - xCB*2] + %define BP_TOP_STACK_EXPR xBP - sCB*9 - xCB*2 +%else + %define VAR_CALLER_MODE [xBP - sCB*6 - xCB*2] + %define BP_TOP_STACK_EXPR xBP - sCB*6 - xCB*2 +%endif + push xBP + mov xBP, xSP +%if TMPL_BITS == 64 + push 0 + mov [rsp+2], es + mov [rsp], ds +%else + push ds + %ifdef TMPL_CMN_R86 + push BS3_SEL_DATA16 + %else + push RT_CONCAT(BS3_SEL_R0_DS,TMPL_BITS) + %endif + pop ds ; DS = BS3KIT_GRPNM_DATA16 or FLAT and we can safely access data + %if TMPL_BITS == 16 && (TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16) + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jbe .prologue_pre_80386 + %endif +%endif + push sBX + push sAX + push sCX + push sDX + push sSI + push sDI +%if TMPL_BITS == 16 + push ebp + push esp + pushfd + %if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16 + jmp .prologue_end + +.prologue_pre_80386: + push bx ; dummy + push bx + xor bx, bx + push bx ; dummy + push ax + push bx ; dummy + push cx + push bx ; dummy + push dx + push bx ; dummy + push si + push bx ; dummy + push di + sub sp, 0ch ; dummy + %endif +%endif +.prologue_end: + + ; + ; VAR_CALLER_MODE: Save the current mode (important for v8086 with 16-bit kernel). + ; + xor xBX, xBX + mov bl, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + push xBX + + ; + ; Dispatch the system call. + ; + cmp ax, BS3_SYSCALL_LAST + ja .invalid_syscall +%if TMPL_BITS == 16 + mov bx, ax + shl bx, 1 + jmp word [cs:.aoffSyscallHandlers + bx] +%else + movzx ebx, ax + mov ebx, [.aoffSyscallHandlers + ebx * 4] + jmp xBX +%endif +.aoffSyscallHandlers: +%ifdef TMPL_16BIT + dw .invalid_syscall wrt CGROUP16 + dw .print_chr wrt CGROUP16 + dw .print_str wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .restore_ctx wrt CGROUP16 +%else + dd .invalid_syscall wrt FLAT + dd .print_chr wrt FLAT + dd .print_str wrt FLAT + dd .to_ringX wrt FLAT + dd .to_ringX wrt FLAT + dd .to_ringX wrt FLAT + dd .to_ringX wrt FLAT + dd .restore_ctx wrt FLAT +%endif + + ; + ; Invalid system call. + ; +.invalid_syscall: + int3 + jmp .return + + ; + ; Print char in the CL register. + ; + ; We use the vga bios teletype interrupt to do the writing, so we must + ; be in some kind of real mode for this to work. 16-bit code segment + ; requried for the mode switching code. + ; +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +.print_chr: +%if TMPL_BITS != 64 + push es + mov di, ss ; Must save and restore SS for supporting 16/32 and 32/16 caller/kernel ring-0 combinations. +%endif +%ifndef TMPL_CMN_R86 + ; Switch to real mode (20h param scratch area not required). + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 +%endif + + ; Print the character, turning '\n' into '\r\n'. + cmp cl, 0ah ; \n + je .print_chr_newline + mov ah, 0eh + mov al, cl + mov bx, 0ff00h + int 10h + jmp .print_chr_done + +.print_chr_newline: + mov ax, 0e0dh ; cmd + \r + mov bx, 0ff00h + int 10h + mov ax, 0e0ah ; cmd + \n + mov bx, 0ff00h + int 10h + +.print_chr_done: +%ifndef TMPL_CMN_R86 + ; Switch back (20h param scratch area not required). + extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + BS3_SET_BITS TMPL_BITS +%endif +%if TMPL_BITS != 64 + mov ss, di + pop es +%endif + jmp .return +TMPL_BEGIN_TEXT + + + ; + ; Prints DX chars from the string pointed to by CX:xSI to the screen. + ; + ; We use the vga bios teletype interrupt to do the writing, so we must + ; be in some kind of real mode for this to work. The string must be + ; accessible from real mode too. + ; +.print_str: +%if TMPL_BITS != 64 + push es + push ss ; Must save and restore SS for supporting 16/32 and 32/16 caller/kernel ring-0 combinations. +%endif + ; Convert the incoming pointer to real mode (assuming caller checked + ; that real mode can access it). + call .convert_ptr_arg_to_real_mode_ax_si + mov cx, VAR_CALLER_DX + + ; Switch to real mode (no 20h scratch required) +%ifndef TMPL_CMN_R86 + %if TMPL_BITS != 16 + jmp .print_str_to_16bit +BS3_BEGIN_TEXT16 +.print_str_to_16bit: + BS3_SET_BITS TMPL_BITS + %endif + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 +%endif + ; Call code in Bs3PrintStrN to do the work. + mov ds, ax + call Bs3PrintStrN_c16_CX_Bytes_At_DS_SI + + ; Switch back (20h param scratch area not required). +%ifndef TMPL_CMN_R86 + extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + %if TMPL_BITS != 16 + BS3_SET_BITS TMPL_BITS + jmp .print_str_end +TMPL_BEGIN_TEXT + %endif +.print_str_end: +%endif +%if TMPL_BITS != 64 + pop ss + pop es +%endif + jmp .return + + + ; + ; Switch the caller to ring-0, ring-1, ring-2 or ring-3. + ; + ; This implement this by saving the entire register context, calling + ; a transformation function (C) and restoring the modified register + ; context using a generic worker. + ; +.to_ringX: + sub xSP, BS3REGCTX_size + mov xBX, xSP ; xBP = BS3REGCTX pointer. + call .save_context + +%if TMPL_BITS == 32 + ; Convert xBP to flat pointer in 32-bit + push ss + push xBX + call Bs3SelProtFar32ToFlat32 + add sSP, 8 + mov xBX, xAX +%endif + push xBX ; Save pointer for the final restore call. + + ; Convert the register context from whatever it is to ring-0. +BONLY64 sub rsp, 10h + mov ax, VAR_CALLER_AX + sub ax, BS3_SYSCALL_TO_RING0 + push xAX +BONLY16 push ss + push xBX + BS3_CALL Bs3RegCtxConvertToRingX, 2 + add xSP, sCB + xCB BS3_ONLY_64BIT(+ 10h) + + ; Restore the register context (does not return). + pop xBX ; restore saved pointer. +BONLY64 sub rsp, 18h +BONLY16 push ss + push xBX + BS3_CALL Bs3RegCtxRestore, 1 + jmp Bs3Panic + + + ; + ; Restore context pointed to by cx:xSI. + ; +.restore_ctx: + call .convert_ptr_arg_to_cx_xSI +BONLY64 sub rsp, 10h + mov xDX, VAR_CALLER_DX + push xDX +BONLY16 push cx + push xSI + BS3_CALL Bs3RegCtxRestore, 2 + jmp Bs3Panic + + ; + ; Return. + ; +.return: + pop xBX ; saved mode + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], bl +%if TMPL_BITS == 16 + and bl, BS3_MODE_CODE_MASK + cmp bl, BS3_MODE_CODE_V86 + je .return_to_v8086_from_16bit_krnl + cmp bl, BS3_MODE_CODE_32 + je .return_to_32bit_from_16bit_krnl + %if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16 + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jbe .return_pre_80386 + %endif + + popfd + pop esp + pop ebp +%endif + pop sDI + pop sSI + pop sDX + pop sCX + pop sAX + pop sBX +%if TMPL_BITS != 64 + pop ds + leave + iret +%else + mov es, [rsp+2] + mov ds, [rsp] + leave ; skips ds + iretq +%endif + +%if TMPL_BITS == 16 + %if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16 + ; Variant of the above for 80286 and older. +.return_pre_80386: + add sp, 0ch + pop di + pop bx ; dummy + pop si + pop bx ; dummy + pop dx + pop bx ; dummy + pop cx + pop bx ; dummy + pop ax + pop bx ; dummy + pop bx ; pushed twice + pop bx + pop ds + pop bp + iret + %endif + +.return_to_v8086_from_16bit_krnl: + int3 + jmp .return_to_v8086_from_16bit_krnl + + ; + ; Returning to 32-bit code may require us to expand and seed the eip + ; and esp addresses in the iret frame since these are truncated when + ; using a 16-bit interrupt handler. + ; + ; Incoming stack: New stack diff cpl: + ; bp + 0ah: [ss] + ; bp + 08h: [sp] bx + 38h: [ss] New stack same cpl: + ; bp + 06h: flags + ; bp + 04h: cs bx + 34h: [esp] bx + 30h: eflags + ; bp + 02h: ip + ; -------------- bx + 30h: eflags bx + 2ch: cs + ; bp + 00h: bp + ; bp - 02h: ds bx + 2ch: cs bx + 28h: eip + ; ------------- + ; bp - 06h: ebx bx + 28h: eip bx + 26h: bp + ; -------------- bx + 24h: ds + ; bp - 0ah: eax bx + 26h: bp + ; bx + 24h: ds bx + 20h: ebx + ; bp - 0eh: ecx + ; bx + 20h: ebx bx + 1ch: eax + ; bp - 12h: edx + ; bx + 1ch: eax bx + 18h: ecx + ; bp - 16h: esi + ; bx + 18h: ecx bx + 14h: edx + ; bp - 1ah: edi + ; bx + 14h: edx bx + 10h: esi + ; bp - 1eh: esp + ; bx + 10h: esi bx + 0ch: edi + ; bp - 22h: ebp + ; bx + 0ch: edi bx + 08h: esp + ; bp - 26h: eflags + ; bx + 08h: esp bx + 04h: ebp + ; + ; bx + 04h: ebp bx + 00h: eflags + ; + ; bx + 00h: eflags + ; + ; + ; If we're returning to the same CPL, we're still using the stack of + ; the 32-bit caller. The high ESP word does not need restoring. + ; + ; If we're returning to a lower CPL, there on a 16-bit ring-0 stack, + ; however, the high ESP word is still that of the caller. + ; +.return_to_32bit_from_16bit_krnl: + mov ax, cs + and al, 3 + mov ah, 3 + and ah, [xBP + xCB*2] + ; The iret frame doubles in size, so allocate more stack. + cmp al, ah + je .return_to_32bit_from_16bit_krnl_same_cpl_sub_sp + sub sp, 2*2 +.return_to_32bit_from_16bit_krnl_same_cpl_sub_sp: + sub sp, 3*2 + mov bx, sp + ; Copy the saved registers. + xor di, di +.return_to_32bit_from_16bit_krnl_copy_loop: + mov ecx, [bp + di - 26h] + mov [ss:bx + di], ecx + add di, 4 + cmp di, 28h + jb .return_to_32bit_from_16bit_krnl_copy_loop + ; Convert the 16-bit iret frame to a 32-bit iret frame. + mov ecx, [BS3_DATA16_WRT(g_uBs3TrapEipHint)] + mov cx, [bp + 02h] ; ip + mov [ss:bx + 28h], ecx + mov ecx, 0f00d0000h + mov cx, [bp + 04h] ; cs + mov [ss:bx + 2ch], ecx + mov ecx, [ss:bx] ; caller eflags + mov cx, [bp + 06h] ; flags + mov [ss:bx + 30h], ecx + cmp al, ah + jz .return_to_32bit_from_16bit_krnl_do_return + mov ecx, [ss:bx + 08h] ; caller esp + mov cx, [bp + 08h] ; sp + mov [ss:bx + 34h], ecx + mov ecx, 0f00d0000h + mov cx, [bp + 0ah] ; ss + mov [ss:bx + 38h], ecx +.return_to_32bit_from_16bit_krnl_do_return: + popfd + pop ecx ; esp - only the high bits! + mov cx, sp + mov esp, ecx + pop ebp + lea bp, [bx + 26h] + pop edi + pop esi + pop edx + pop ecx + pop eax + pop ebx + pop ds + leave + iretd + +%endif ; 16-bit + + + ; + ; Internal function. ss:xBX = Pointer to register frame (BS3REGCTX). + ; @uses xAX + ; +.save_context: +%if TMPL_BITS == 16 + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386 + jae .save_context_full + + ; + ; 80286 or earlier. + ; + + ; Clear the state area first. + push di + xor di, di +.save_context_16_clear_loop: + mov word [ss:bx + di], 0 + mov word [ss:bx + di + 2], 0 + mov word [ss:bx + di + 4], 0 + mov word [ss:bx + di + 6], 0 + add di, 8 + cmp di, BS3REGCTX_size + jb .save_context_16_clear_loop + pop di + + ; Do the 8086/80186/80286 state saving. + mov ax, VAR_CALLER_AX + mov [ss:bx + BS3REGCTX.rax], ax + mov cx, VAR_CALLER_CX + mov [ss:bx + BS3REGCTX.rcx], ax + mov ax, VAR_CALLER_DX + mov [ss:bx + BS3REGCTX.rdx], ax + mov ax, VAR_CALLER_BX + mov [ss:bx + BS3REGCTX.rbx], ax + mov [ss:bx + BS3REGCTX.rsi], si + mov [ss:bx + BS3REGCTX.rdi], di + mov ax, VAR_CALLER_BP + mov [ss:bx + BS3REGCTX.rbp], ax + mov ax, VAR_CALLER_DS + mov [ss:bx + BS3REGCTX.ds], ax + mov [ss:bx + BS3REGCTX.es], es + mov ax, [xBP + xCB] + mov [ss:bx + BS3REGCTX.rip], ax + mov ax, [xBP + xCB*2] + mov [ss:bx + BS3REGCTX.cs], ax + and al, X86_SEL_RPL + mov [ss:bx + BS3REGCTX.bCpl], al + cmp al, 0 + je .save_context_16_same + mov ax, [xBP + xCB*4] + mov [ss:bx + BS3REGCTX.rsp], ax + mov ax, [xBP + xCB*5] + mov [ss:bx + BS3REGCTX.ss], ax + jmp .save_context_16_done_stack +.save_context_16_same: + mov ax, bp + add ax, xCB * (1 + 3) + mov [ss:bx + BS3REGCTX.rsp], ax + mov ax, ss + mov [ss:bx + BS3REGCTX.ss], ax +.save_context_16_done_stack: + mov ax, [xBP + xCB*3] + mov [ss:bx + BS3REGCTX.rflags], ax + mov al, VAR_CALLER_MODE + mov [ss:bx + BS3REGCTX.bMode], al + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jne .save_context_16_return + smsw [ss:bx + BS3REGCTX.cr0] + str [ss:bx + BS3REGCTX.tr] + sldt [ss:bx + BS3REGCTX.ldtr] +.save_context_16_return: + or byte [ss:bx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 | BS3REG_CTX_F_NO_CR4 + ret +%endif ; TMPL_BITS == 16 + + ; + ; 80386 or later. + ; +.save_context_full: + + ; Clear the state area. + push xDI + xor xDI, xDI + AssertCompileSizeAlignment(BS3REGCTX, 16) +.save_context_full_clear_loop: +%if TMPL_BITS != 64 + mov dword [ss:xBX + xDI], 0 + mov dword [ss:xBX + xDI + 4], 0 + add xDI, 8 +%else + mov qword [xBX + xDI], 0 + mov qword [xBX + xDI + 8], 0 + add xDI, 10h +%endif + cmp xDI, BS3REGCTX_size + jb .save_context_full_clear_loop + pop xDI + + ; Do the 386+ state saving. +%if TMPL_BITS == 16 ; save the high word of registered pushed on the stack. + mov ecx, VAR_CALLER_AX + mov [ss:bx + BS3REGCTX.rax], ecx + mov ecx, VAR_CALLER_CX + mov [ss:bx + BS3REGCTX.rcx], ecx + mov ecx, VAR_CALLER_DX + mov [ss:bx + BS3REGCTX.rdx], ecx + mov ecx, VAR_CALLER_BX + mov [ss:bx + BS3REGCTX.rbx], ecx + mov ecx, VAR_CALLER_EBP + mov [ss:bx + BS3REGCTX.rbp], ecx + mov ecx, VAR_CALLER_ESP + mov [ss:bx + BS3REGCTX.rsp], ecx + mov ecx, VAR_CALLER_SI + mov [ss:bx + BS3REGCTX.rsi], ecx + mov ecx, VAR_CALLER_DI + mov [ss:bx + BS3REGCTX.rdi], ecx + mov ecx, VAR_CALLER_EFLAGS + mov [ss:bx + BS3REGCTX.rflags], ecx + + ; Seed high EIP word if 32-bit CS. + lar ecx, [bp + 4] + jnz .save_context_full_done_16bit_high_word + test ecx, X86LAR_F_D + jz .save_context_full_done_16bit_high_word + mov ecx, [BS3_DATA16_WRT(g_uBs3TrapEipHint)] + mov [ss:bx + BS3REGCTX.rip], ecx +.save_context_full_done_16bit_high_word: +%endif ; 16-bit + mov xAX, VAR_CALLER_AX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rax], xAX + mov xCX, VAR_CALLER_CX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rcx], xCX + mov xAX, VAR_CALLER_DX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rdx], xAX + mov xAX, VAR_CALLER_BX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rbx], xAX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsi], sSI + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rdi], sDI + mov xAX, VAR_CALLER_BP + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rbp], xAX +%if TMPL_BITS != 64 + mov ax, VAR_CALLER_DS + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ds], ax +%else + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ds], ds +%endif + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.es], es + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.fs], fs + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.gs], gs + mov xAX, [xBP + xCB] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rip], xAX + mov ax, [xBP + xCB*2] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cs], ax +%if TMPL_MODE != BS3_MODE_RM + and al, X86_SEL_RPL + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bCpl], al + cmp al, 0 + je .save_context_full_same + mov xAX, [xBP + xCB*4] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsp], xAX + mov ax, [xBP + xCB*5] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ss], ax + jmp .save_context_full_done_stack +%else + mov byte [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bCpl], 0 +%endif +.save_context_full_same: + mov xAX, xBP + add xAX, xCB * (1 + 3) + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsp], xAX + mov ax, ss + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ss], ax +.save_context_full_done_stack: + mov xAX, [xBP + xCB*3] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rflags], xAX + + mov al, VAR_CALLER_MODE + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bMode], al +%if TMPL_BITS == 64 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r8], r8 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r9], r9 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r10], r10 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r11], r11 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r12], r12 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r13], r13 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r14], r14 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r15], r15 +%endif + str [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.tr] + sldt [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ldtr] + mov sAX, cr0 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr0], sAX + mov sAX, cr2 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr2], sAX + mov sAX, cr3 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr3], sAX +%if TMPL_BITS != 64 + test byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) + jnz .have_cr4 + or byte [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + jmp .done_cr4 +.have_cr4: +%endif + mov sAX, cr4 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr4], sAX +%if TMPL_BITS != 64 +.done_cr4: + or byte [ss:xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 + + ; Deal with extended v8086 frame. + %if TMPL_BITS == 32 + test dword [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rflags], X86_EFL_VM + jz .save_context_full_return + %else + test byte VAR_CALLER_MODE, BS3_MODE_CODE_V86 + jz .save_context_full_return + mov dword [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rflags], X86_EFL_VM + %endif + mov xAX, [xBP + xCB*4] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsp], xAX + mov ax, [xBP + xCB*5] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ss], ax + mov ax, [xBP + xCB*6] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.es], ax + mov ax, [xBP + xCB*7] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ds], ax + mov ax, [xBP + xCB*8] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.fs], ax + mov ax, [xBP + xCB*9] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.gs], ax + mov byte [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bCpl], 3 + jmp .save_context_full_return + +%endif ; !64-bit + +.save_context_full_return: + ret + +%if TMPL_BITS == 16 + CPU 286 +%endif + + ; + ; Internal function for converting a syscall pointer parameter (cx:xSI) + ; to a pointer we can use here in this context. + ; + ; Returns the result in cx:xSI. + ; @uses xAX, xCX, xDX + ; +.convert_ptr_arg_to_cx_xSI: + call .convert_ptr_arg_to_flat +%if TMPL_BITS == 16 + ; Convert to tiled address. + mov si, ax ; offset. + shl dx, X86_SEL_SHIFT + add dx, BS3_SEL_TILED + mov cx, dx +%else + ; Just supply a flat selector. + mov xSI, xAX + mov cx, ds +%endif + ret + + ; + ; Internal function for converting a syscall pointer parameter (caller CX:xSI) + ; to a real mode pointer. + ; + ; Returns the result in AX:SI. + ; @uses xAX, xCX, xDX + ; +.convert_ptr_arg_to_real_mode_ax_si: + call .convert_ptr_arg_to_flat + mov si, ax +%if TMPL_BITS == 16 + mov ax, dx +%else + shr eax, 16 +%endif + shl ax, 12 + ret + + ; + ; Internal function for the above that wraps the Bs3SelProtFar32ToFlat32 call. + ; + ; @returns eax (32-bit, 64-bit), dx+ax (16-bit). + ; @uses eax, ecx, edx + ; +.convert_ptr_arg_to_flat: +%if TMPL_BITS == 16 + ; Convert to (32-bit) flat address first. + test byte VAR_CALLER_MODE, BS3_MODE_CODE_V86 + jz .convert_ptr_arg_to_flat_prot_16 + + mov ax, VAR_CALLER_CX + mov dx, ax + shl ax, 4 + shr dx, 12 + add ax, VAR_CALLER_SI + adc dx, 0 + ret + +.convert_ptr_arg_to_flat_prot_16: + push es + push bx + push word VAR_CALLER_CX ; selector + xor ax, ax + test byte VAR_CALLER_MODE, BS3_MODE_CODE_16 + jnz .caller_is_16_bit + mov ax, VAR_CALLER_SI_HI +.caller_is_16_bit: + push ax ; offset high + push word VAR_CALLER_SI ; offset low + call Bs3SelProtFar32ToFlat32 + add sp, 2*3 + pop bx + pop es + ret + +%else ; 32 or 64 bit + test byte VAR_CALLER_MODE, BS3_MODE_CODE_V86 + jz .convert_ptr_arg_to_cx_xSI_prot + + ; Convert real mode address to flat address and return it. + movzx eax, word VAR_CALLER_CX + shl eax, 4 + movzx edx, word VAR_CALLER_SI + add eax, edx + ret + + ; Convert to (32-bit) flat address. +.convert_ptr_arg_to_cx_xSI_prot: + %if TMPL_BITS == 64 + push r11 + push r10 + push r9 + push r8 + sub rsp, 10h + %endif + movzx ecx, word VAR_CALLER_CX + push xCX + mov eax, VAR_CALLER_SI + test byte VAR_CALLER_MODE, BS3_MODE_CODE_16 + jz .no_masking_offset + and eax, 0ffffh +.no_masking_offset: + push xAX + BS3_CALL Bs3SelProtFar32ToFlat32,2 + add xSP, xCB*2 BS3_ONLY_64BIT(+ 10h) + %if TMPL_BITS == 64 + pop r8 + pop r9 + pop r10 + pop r11 + %endif +%endif + ret + +BS3_PROC_END_MODE Bs3TrapSystemCallHandler + |