; $Id: cidet-appA.asm $ ;; @file ; CPU Instruction Decoding & Execution Tests - Ring-3 Driver Application, Assembly Code. ; ; ; Copyright (C) 2009-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 . ; ; 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 "iprt/asmdefs.mac" %include "iprt/x86.mac" %include "cidet.mac" ;******************************************************************************* ;* Global Variables * ;******************************************************************************* %ifdef RT_ARCH_X86 ;; Used by CidetAppSaveAndRestoreCtx when we have a tricky target stack. g_uTargetEip dd 0 g_uTargetCs dw 0 %endif ;; ; Leave GS alone on 64-bit darwin (gs is 0, no ldt or gdt entry to load that'll ; restore the lower 32-bits of the base when saving and restoring the register). %ifdef RT_OS_DARWIN %ifdef RT_ARCH_AMD64 %define CIDET_LEAVE_GS_ALONE %endif %endif BEGINCODE ;; ; ASSUMES that it's called and the EIP/RIP is found on the stack. ; ; @param pSaveCtx ds:xCX The context to save; DS, xDX and xCX have ; already been saved by the caller. ; @param pRestoreCtx ds:xDX The context to restore. ; BEGINPROC CidetAppSaveAndRestoreCtx ; ; Save the stack pointer and program counter first so we can later ; bypass this step if we need to. ; mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xAX * 8], xAX ; need scratch register. lea xAX, [xSP + xCB] mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xSP * 8], xAX mov word [xCX + CIDETCPUCTX.aSRegs + X86_SREG_SS * 2], ss mov word [xCX + CIDETCPUCTX.aSRegs + X86_SREG_CS * 2], cs mov xAX, [xSP] mov [xCX + CIDETCPUCTX.rip], xAX jmp CidetAppSaveAndRestoreCtx_1 GLOBALNAME CidetAppSaveAndRestoreCtx_NoSsSpCsIp mov [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xAX * 8], xAX CidetAppSaveAndRestoreCtx_1: ; Flags. %ifdef RT_ARCH_AMD64 pushfq %else pushfd %endif pop xAX mov [xCX + CIDETCPUCTX.rfl], xAX ; Segment registers. mov word [xCX + CIDETCPUCTX.aSRegs + X86_SREG_ES * 2], es mov word [xCX + CIDETCPUCTX.aSRegs + X86_SREG_FS * 2], fs mov word [xCX + CIDETCPUCTX.aSRegs + X86_SREG_GS * 2], gs ; Remaining GPRs. mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xBX * 8], xBX mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xBP * 8], xBP mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xSI * 8], xSI mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xDI * 8], xDI %ifdef RT_ARCH_AMD64 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x8 * 8], r8 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x9 * 8], r9 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x10 * 8], r10 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x11 * 8], r11 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x12 * 8], r12 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x13 * 8], r13 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x14 * 8], r14 mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x15 * 8], r15 xor eax, eax mov [xCX + CIDETCPUCTX.cr2], rax %ifndef CIDET_REDUCED_CTX mov [xCX + CIDETCPUCTX.cr0], rax mov [xCX + CIDETCPUCTX.cr3], rax mov [xCX + CIDETCPUCTX.cr4], rax mov [xCX + CIDETCPUCTX.cr8], rax mov [xCX + CIDETCPUCTX.dr0], rax mov [xCX + CIDETCPUCTX.dr1], rax mov [xCX + CIDETCPUCTX.dr2], rax mov [xCX + CIDETCPUCTX.dr3], rax mov [xCX + CIDETCPUCTX.dr6], rax mov [xCX + CIDETCPUCTX.dr7], rax mov [xCX + CIDETCPUCTX.tr], ax mov [xCX + CIDETCPUCTX.ldtr], ax %endif %else xor eax, eax mov [xCX + CIDETCPUCTX.rfl + 4], eax mov [xCX + CIDETCPUCTX.rip + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xAX * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xCX * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xDX * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xBX * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xSP * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xBP * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xSI * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xDI * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x8 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x8 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x9 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x9 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x10 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x10 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x11 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x11 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x12 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x12 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x13 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x13 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x14 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x14 * 8 + 4], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x15 * 8 ], eax mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_x15 * 8 + 4], eax mov [xCX + CIDETCPUCTX.cr2 ], eax mov [xCX + CIDETCPUCTX.cr2 + 4], eax %ifndef CIDET_REDUCED_CTX mov [xCX + CIDETCPUCTX.cr0 ], eax mov [xCX + CIDETCPUCTX.cr0 + 4], eax mov [xCX + CIDETCPUCTX.cr3 ], eax mov [xCX + CIDETCPUCTX.cr3 + 4], eax mov [xCX + CIDETCPUCTX.cr4 ], eax mov [xCX + CIDETCPUCTX.cr4 + 4], eax mov [xCX + CIDETCPUCTX.cr8 ], eax mov [xCX + CIDETCPUCTX.cr8 + 4], eax mov [xCX + CIDETCPUCTX.dr0 ], eax mov [xCX + CIDETCPUCTX.dr0 + 4], eax mov [xCX + CIDETCPUCTX.dr1 ], eax mov [xCX + CIDETCPUCTX.dr1 + 4], eax mov [xCX + CIDETCPUCTX.dr2 ], eax mov [xCX + CIDETCPUCTX.dr2 + 4], eax mov [xCX + CIDETCPUCTX.dr3 ], eax mov [xCX + CIDETCPUCTX.dr3 + 4], eax mov [xCX + CIDETCPUCTX.dr6 ], eax mov [xCX + CIDETCPUCTX.dr6 + 4], eax mov [xCX + CIDETCPUCTX.dr7 ], eax mov [xCX + CIDETCPUCTX.dr7 + 4], eax mov [xCX + CIDETCPUCTX.tr], ax mov [xCX + CIDETCPUCTX.ldtr], ax %endif %endif dec xAX mov [xCX + CIDETCPUCTX.uErr], xAX %ifdef RT_ARCH_X86 mov [xCX + CIDETCPUCTX.uErr + 4], eax %endif mov [xCX + CIDETCPUCTX.uXcpt], eax ; ; Restore the other state (pointer in xDX). ; NAME(CidetAppSaveAndRestoreCtx_Restore): ; Restore ES, FS, and GS. mov es, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_ES * 2] mov fs, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_FS * 2] %ifndef CIDET_LEAVE_GS_ALONE mov gs, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_GS * 2] %endif ; Restore most GPRs (except xCX, xAX and xSP). mov xCX, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xCX * 8] mov xBX, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xBX * 8] mov xBP, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xBP * 8] mov xSI, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xSI * 8] mov xDI, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xDI * 8] %ifdef RT_ARCH_AMD64 mov r8, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x8 * 8] mov r9, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x9 * 8] mov r10, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x10 * 8] mov r11, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x11 * 8] mov r12, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x12 * 8] mov r13, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x13 * 8] mov r14, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x14 * 8] mov r15, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_x15 * 8] %endif %ifdef RT_ARCH_AMD64 ; Create an iret frame which restores SS:RSP, RFLAGS, and CS:RIP. movzx eax, word [xDX + CIDETCPUCTX.aSRegs + X86_SREG_SS * 2] push xAX push qword [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xSP * 8] push qword [xDX + CIDETCPUCTX.rfl] movzx eax, word [xDX + CIDETCPUCTX.aSRegs + X86_SREG_CS * 2] push xAX push qword [xDX + CIDETCPUCTX.rip] ; Restore DS, xAX and xDX then do the iret. mov ds, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_DS * 2] mov xAX, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xAX * 8] mov xDX, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xDX * 8] iretq %else ; In 32-bit mode iret doesn't restore CS:ESP for us, so we have to ; make a choice whether the SS:ESP is more important than EFLAGS. cmp byte [xDX + CIDETCPUCTX.fTrickyStack], 0 jne .tricky_stack mov ss, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_SS * 2] mov xSP, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xSP * 8] push dword [xDX + CIDETCPUCTX.rfl] ; iret frame movzx eax, word [xDX + CIDETCPUCTX.aSRegs + X86_SREG_CS * 2] ; iret frame push xAX ; iret frame push dword [xDX + CIDETCPUCTX.rip] ; iret frame mov xAX, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xAX * 8] mov ds, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_DS * 2] mov xDX, [cs:xDX + CIDETCPUCTX.aGRegs + X86_GREG_xDX * 8] iretd .tricky_stack: mov xAX, [xDX + CIDETCPUCTX.rip] mov [g_uTargetEip], xAX mov ax, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_CS * 2] mov [g_uTargetCs], ax push dword [xDX + CIDETCPUCTX.rfl] popfd mov ss, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_SS * 2] mov xSP, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xSP * 8] mov xAX, [xDX + CIDETCPUCTX.aGRegs + X86_GREG_xAX * 8] mov ds, [xDX + CIDETCPUCTX.aSRegs + X86_SREG_DS * 2] mov xDX, [cs:xDX + CIDETCPUCTX.aGRegs + X86_GREG_xDX * 8] jmp far [cs:g_uTargetEip] %endif ENDPROC CidetAppSaveAndRestoreCtx ;; ; C callable version of CidetAppSaveAndRestoreCtx more or less. ; ; @param pSaveCtx x86:esp+4 gcc:rdi msc:rcx ; @param pRestoreCtx x86:esp+8 gcc:rsi msc:rdx BEGINPROC CidetAppExecute %ifdef RT_ARCH_X86 mov ecx, [esp + 4] mov edx, [esp + 8] %elifdef ASM_CALL64_GCC mov rcx, rdi mov rdx, rsi %elifndef ASM_CALL64_MSC %error "unsupport arch." %endif mov word [xCX + CIDETCPUCTX.aSRegs + X86_SREG_DS * 2], ds mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xDX * 8], xDX mov [xCX + CIDETCPUCTX.aGRegs + X86_GREG_xCX * 8], xCX jmp NAME(CidetAppSaveAndRestoreCtx) ENDPROC CidetAppExecute ;; ; C callable restore function. ; ; @param pRestoreCtx x86:esp+4 gcc:rdi msc:rcx BEGINPROC CidetAppRestoreCtx %ifdef RT_ARCH_X86 mov edx, [esp + 4] %elifdef ASM_CALL64_GCC mov rdx, rdi %elifdef ASM_CALL64_MSC mov rdx, rcx %else %error "unsupport arch." %endif mov ds, [cs:xDX + CIDETCPUCTX.aSRegs + X86_SREG_DS * 2] jmp NAME(CidetAppSaveAndRestoreCtx_Restore) ENDPROC CidetAppRestoreCtx