diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm')
-rw-r--r-- | src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm b/src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm new file mode 100644 index 00000000..365bfdcf --- /dev/null +++ b/src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm @@ -0,0 +1,395 @@ +; $Id: VMMR0JmpA-x86.asm $ +;; @file +; VMM - R0 SetJmp / LongJmp routines for X86. +; + +; +; Copyright (C) 2006-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>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "VBox/asmdefs.mac" +%include "VMMInternal.mac" +%include "VBox/err.mac" +%include "VBox/param.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +%define RESUME_MAGIC 07eadf00dh +%define STACK_PADDING 0eeeeeeeeh + + + +BEGINCODE + + +;; +; The setjmp variant used for calling Ring-3. +; +; This differs from the normal setjmp in that it will resume VMMRZCallRing3 if we're +; in the middle of a ring-3 call. Another differences is the function pointer and +; argument. This has to do with resuming code and the stack frame of the caller. +; +; @returns VINF_SUCCESS on success or whatever is passed to vmmR0CallRing3LongJmp. +; @param pJmpBuf msc:rcx gcc:rdi x86:[esp+0x04] Our jmp_buf. +; @param pfn msc:rdx gcc:rsi x86:[esp+0x08] The function to be called when not resuming. +; @param pvUser1 msc:r8 gcc:rdx x86:[esp+0x0c] The argument of that function. +; @param pvUser2 msc:r9 gcc:rcx x86:[esp+0x10] The argument of that function. +; +BEGINPROC vmmR0CallRing3SetJmp +GLOBALNAME vmmR0CallRing3SetJmp2 +GLOBALNAME vmmR0CallRing3SetJmpEx + ; + ; Save the registers. + ; + mov edx, [esp + 4h] ; pJmpBuf + mov [xDX + VMMR0JMPBUF.ebx], ebx + mov [xDX + VMMR0JMPBUF.esi], esi + mov [xDX + VMMR0JMPBUF.edi], edi + mov [xDX + VMMR0JMPBUF.ebp], ebp + mov xAX, [esp] + mov [xDX + VMMR0JMPBUF.eip], xAX + lea ecx, [esp + 4] ; (used in resume) + mov [xDX + VMMR0JMPBUF.esp], ecx + pushf + pop xAX + mov [xDX + VMMR0JMPBUF.eflags], xAX + + ; + ; If we're not in a ring-3 call, call pfn and return. + ; + test byte [xDX + VMMR0JMPBUF.fInRing3Call], 1 + jnz .resume + + mov ebx, edx ; pJmpBuf -> ebx (persistent reg) +%ifdef VMM_R0_SWITCH_STACK + mov esi, [ebx + VMMR0JMPBUF.pvSavedStack] + test esi, esi + jz .entry_error + %ifdef VBOX_STRICT + cmp dword [esi], 0h + jne .entry_error + mov edx, esi + mov edi, esi + mov ecx, VMM_STACK_SIZE / 4 + mov eax, STACK_PADDING + repne stosd + %endif + lea esi, [esi + VMM_STACK_SIZE - 32] + mov [esi + 1ch], dword 0deadbeefh ; Marker 1. + mov [esi + 18h], ebx ; Save pJmpBuf pointer. + mov [esi + 14h], dword 00c00ffeeh ; Marker 2. + mov [esi + 10h], dword 0f00dbeefh ; Marker 3. + mov edx, [esp + 10h] ; pvArg2 + mov ecx, [esp + 0ch] ; pvArg1 + mov eax, [esp + 08h] ; pfn + %if 1 ; Use this to eat of some extra stack - handy for finding paths using lots of stack. + %define FRAME_OFFSET 0 + %else + %define FRAME_OFFSET 1024 + %endif + mov [esi - FRAME_OFFSET + 04h], edx + mov [esi - FRAME_OFFSET ], ecx + lea esp, [esi - FRAME_OFFSET] ; Switch stack! + call eax + and dword [esi + 1ch], byte 0 ; reset marker. + + %ifdef VBOX_STRICT + ; Calc stack usage and check for overflows. + mov edi, [ebx + VMMR0JMPBUF.pvSavedStack] + cmp dword [edi], STACK_PADDING ; Check for obvious stack overflow. + jne .stack_overflow + mov esi, eax ; save eax + mov eax, STACK_PADDING + mov ecx, VMM_STACK_SIZE / 4 + cld + repe scasd + shl ecx, 2 ; *4 + cmp ecx, VMM_STACK_SIZE - 64 ; Less than 64 bytes left -> overflow as well. + mov eax, esi ; restore eax in case of overflow (esi remains used) + jae .stack_overflow_almost + + ; Update stack usage statistics. + cmp ecx, [ebx + VMMR0JMPBUF.cbUsedMax] ; New max usage? + jle .no_used_max + mov [ebx + VMMR0JMPBUF.cbUsedMax], ecx +.no_used_max: + ; To simplify the average stuff, just historize before we hit div errors. + inc dword [ebx + VMMR0JMPBUF.cUsedTotal] + test [ebx + VMMR0JMPBUF.cUsedTotal], dword 0c0000000h + jz .no_historize + mov dword [ebx + VMMR0JMPBUF.cUsedTotal], 2 + mov edi, [ebx + VMMR0JMPBUF.cbUsedAvg] + mov [ebx + VMMR0JMPBUF.cbUsedTotal], edi + mov dword [ebx + VMMR0JMPBUF.cbUsedTotal + 4], 0 +.no_historize: + add [ebx + VMMR0JMPBUF.cbUsedTotal], ecx + adc dword [ebx + VMMR0JMPBUF.cbUsedTotal + 4], 0 + mov eax, [ebx + VMMR0JMPBUF.cbUsedTotal] + mov edx, [ebx + VMMR0JMPBUF.cbUsedTotal + 4] + mov edi, [ebx + VMMR0JMPBUF.cUsedTotal] + div edi + mov [ebx + VMMR0JMPBUF.cbUsedAvg], eax + + mov eax, esi ; restore eax (final, esi released) + + mov edi, [ebx + VMMR0JMPBUF.pvSavedStack] + mov dword [edi], 0h ; Reset the overflow marker. + %endif ; VBOX_STRICT + +%else ; !VMM_R0_SWITCH_STACK + mov ecx, [esp + 0ch] ; pvArg1 + mov edx, [esp + 10h] ; pvArg2 + mov eax, [esp + 08h] ; pfn + sub esp, 12 ; align the stack on a 16-byte boundary. + mov [esp ], ecx + mov [esp + 04h], edx + call eax +%endif ; !VMM_R0_SWITCH_STACK + mov edx, ebx ; pJmpBuf -> edx (volatile reg) + + ; + ; Return like in the long jump but clear eip, no short cuts here. + ; +.proper_return: + mov ebx, [xDX + VMMR0JMPBUF.ebx] + mov esi, [xDX + VMMR0JMPBUF.esi] + mov edi, [xDX + VMMR0JMPBUF.edi] + mov ebp, [xDX + VMMR0JMPBUF.ebp] + mov xCX, [xDX + VMMR0JMPBUF.eip] + and dword [xDX + VMMR0JMPBUF.eip], byte 0 ; used for valid check. + mov esp, [xDX + VMMR0JMPBUF.esp] + push dword [xDX + VMMR0JMPBUF.eflags] + popf + jmp xCX + +.entry_error: + mov eax, VERR_VMM_SET_JMP_ERROR + jmp .proper_return + +.stack_overflow: + mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW + mov edx, ebx + jmp .proper_return + +.stack_overflow_almost: + mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW + mov edx, ebx + jmp .proper_return + + ; + ; Aborting resume. + ; +.bad: + and dword [xDX + VMMR0JMPBUF.eip], byte 0 ; used for valid check. + mov edi, [xDX + VMMR0JMPBUF.edi] + mov esi, [xDX + VMMR0JMPBUF.esi] + mov ebx, [xDX + VMMR0JMPBUF.ebx] + mov eax, VERR_VMM_SET_JMP_ABORTED_RESUME + ret + + ; + ; Resume VMMRZCallRing3 the call. + ; +.resume: + ; Sanity checks. +%ifdef VMM_R0_SWITCH_STACK + mov eax, [xDX + VMMR0JMPBUF.pvSavedStack] + %ifdef RT_STRICT + cmp dword [eax], STACK_PADDING + %endif + lea eax, [eax + VMM_STACK_SIZE - 32] + cmp dword [eax + 1ch], 0deadbeefh ; Marker 1. + jne .bad + %ifdef RT_STRICT + cmp [esi + 18h], edx ; The saved pJmpBuf pointer. + jne .bad + cmp dword [esi + 14h], 00c00ffeeh ; Marker 2. + jne .bad + cmp dword [esi + 10h], 0f00dbeefh ; Marker 3. + jne .bad + %endif +%else ; !VMM_R0_SWITCH_STACK + cmp ecx, [xDX + VMMR0JMPBUF.SpCheck] + jne .bad +.espCheck_ok: + mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack] + cmp ecx, VMM_STACK_SIZE + ja .bad + test ecx, 3 + jnz .bad + mov edi, [xDX + VMMR0JMPBUF.esp] + sub edi, [xDX + VMMR0JMPBUF.SpResume] + cmp ecx, edi + jne .bad +%endif + +%ifdef VMM_R0_SWITCH_STACK + ; Switch stack. + mov esp, [xDX + VMMR0JMPBUF.SpResume] +%else + ; Restore the stack. + mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack] + shr ecx, 2 + mov esi, [xDX + VMMR0JMPBUF.pvSavedStack] + mov edi, [xDX + VMMR0JMPBUF.SpResume] + mov esp, edi + rep movsd +%endif ; !VMM_R0_SWITCH_STACK + mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 0 + + ; + ; Continue where we left off. + ; +%ifdef VBOX_STRICT + pop eax ; magic + cmp eax, RESUME_MAGIC + je .magic_ok + mov ecx, 0123h + mov [ecx], edx +.magic_ok: +%endif + popf + pop ebx + pop esi + pop edi + pop ebp + xor eax, eax ; VINF_SUCCESS + ret +ENDPROC vmmR0CallRing3SetJmp + + +;; +; Worker for VMMRZCallRing3. +; This will save the stack and registers. +; +; @param pJmpBuf msc:rcx gcc:rdi x86:[ebp+8] Pointer to the jump buffer. +; @param rc msc:rdx gcc:rsi x86:[ebp+c] The return code. +; +BEGINPROC vmmR0CallRing3LongJmp + ; + ; Save the registers on the stack. + ; + push ebp + mov ebp, esp + push edi + push esi + push ebx + pushf +%ifdef VBOX_STRICT + push RESUME_MAGIC +%endif + + ; + ; Load parameters. + ; + mov edx, [ebp + 08h] ; pJmpBuf + mov eax, [ebp + 0ch] ; rc + + ; + ; Is the jump buffer armed? + ; + cmp dword [xDX + VMMR0JMPBUF.eip], byte 0 + je .nok + + ; + ; Sanity checks. + ; + mov edi, [xDX + VMMR0JMPBUF.pvSavedStack] + test edi, edi ; darwin may set this to 0. + jz .nok + mov [xDX + VMMR0JMPBUF.SpResume], esp +%ifndef VMM_R0_SWITCH_STACK + mov esi, esp + mov ecx, [xDX + VMMR0JMPBUF.esp] + sub ecx, esi + + ; two sanity checks on the size. + cmp ecx, VMM_STACK_SIZE ; check max size. + jnbe .nok + + ; + ; Copy the stack. + ; + test ecx, 3 ; check alignment + jnz .nok + mov [xDX + VMMR0JMPBUF.cbSavedStack], ecx + shr ecx, 2 + rep movsd +%endif ; !VMM_R0_SWITCH_STACK + + ; Save a PC here to assist unwinding. +.unwind_point: + mov dword [xDX + VMMR0JMPBUF.SavedEipForUnwind], .unwind_point + mov ecx, [xDX + VMMR0JMPBUF.ebp] + lea ecx, [ecx + 4] + mov [xDX + VMMR0JMPBUF.UnwindRetPcLocation], ecx + + ; Save ESP & EBP to enable stack dumps + mov ecx, ebp + mov [xDX + VMMR0JMPBUF.SavedEbp], ecx + sub ecx, 4 + mov [xDX + VMMR0JMPBUF.SavedEsp], ecx + + ; store the last pieces of info. + mov ecx, [xDX + VMMR0JMPBUF.esp] + mov [xDX + VMMR0JMPBUF.SpCheck], ecx + mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 1 + + ; + ; Do the long jump. + ; + mov ebx, [xDX + VMMR0JMPBUF.ebx] + mov esi, [xDX + VMMR0JMPBUF.esi] + mov edi, [xDX + VMMR0JMPBUF.edi] + mov ebp, [xDX + VMMR0JMPBUF.ebp] + mov ecx, [xDX + VMMR0JMPBUF.eip] + mov [xDX + VMMR0JMPBUF.UnwindRetPcValue], ecx + mov esp, [xDX + VMMR0JMPBUF.esp] + push dword [xDX + VMMR0JMPBUF.eflags] + popf + jmp ecx + + ; + ; Failure + ; +.nok: +%ifdef VBOX_STRICT + pop eax ; magic + cmp eax, RESUME_MAGIC + je .magic_ok + mov ecx, 0123h + mov [ecx], edx +.magic_ok: +%endif + popf + pop ebx + pop esi + pop edi + mov eax, VERR_VMM_LONG_JMP_ERROR + leave + ret +ENDPROC vmmR0CallRing3LongJmp + |