summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm')
-rw-r--r--src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm491
1 files changed, 491 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm b/src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm
new file mode 100644
index 00000000..8735dfa6
--- /dev/null
+++ b/src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm
@@ -0,0 +1,491 @@
+; $Id: VMMR0JmpA-amd64.asm $
+;; @file
+; VMM - R0 SetJmp / LongJmp routines for AMD64.
+;
+
+;
+; Copyright (C) 2006-2019 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.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%define RT_ASM_WITH_SEH64
+%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 0eeeeeeeeeeeeeeeeh
+
+;; Workaround for linux 4.6 fast/slow syscall stack depth difference.
+%ifdef VMM_R0_SWITCH_STACK
+ %define STACK_FUZZ_SIZE 0
+%else
+ %define STACK_FUZZ_SIZE 128
+%endif
+
+
+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.
+ ;
+ push rbp
+ SEH64_PUSH_xBP
+ mov rbp, rsp
+ SEH64_SET_FRAME_xBP 0
+ %ifdef ASM_CALL64_MSC
+ sub rsp, 30h + STACK_FUZZ_SIZE ; (10h is used by resume (??), 20h for callee spill area)
+ SEH64_ALLOCATE_STACK 30h + STACK_FUZZ_SIZE
+SEH64_END_PROLOGUE
+ mov r11, rdx ; pfn
+ mov rdx, rcx ; pJmpBuf;
+ %else
+ sub rsp, 10h + STACK_FUZZ_SIZE ; (10h is used by resume (??))
+ SEH64_ALLOCATE_STACK 10h + STACK_FUZZ_SIZE
+SEH64_END_PROLOGUE
+ mov r8, rdx ; pvUser1 (save it like MSC)
+ mov r9, rcx ; pvUser2 (save it like MSC)
+ mov r11, rsi ; pfn
+ mov rdx, rdi ; pJmpBuf
+ %endif
+ mov [xDX + VMMR0JMPBUF.rbx], rbx
+ %ifdef ASM_CALL64_MSC
+ mov [xDX + VMMR0JMPBUF.rsi], rsi
+ mov [xDX + VMMR0JMPBUF.rdi], rdi
+ %endif
+ mov [xDX + VMMR0JMPBUF.rbp], rbp
+ mov [xDX + VMMR0JMPBUF.r12], r12
+ mov [xDX + VMMR0JMPBUF.r13], r13
+ mov [xDX + VMMR0JMPBUF.r14], r14
+ mov [xDX + VMMR0JMPBUF.r15], r15
+ mov xAX, [rbp + 8] ; (not really necessary, except for validity check)
+ mov [xDX + VMMR0JMPBUF.rip], xAX
+ %ifdef ASM_CALL64_MSC
+ lea r10, [rsp + 20h] ; must save the spill area
+ %else
+ lea r10, [rsp]
+ %endif
+ mov [xDX + VMMR0JMPBUF.rsp], r10
+ %ifdef RT_OS_WINDOWS
+ movdqa [xDX + VMMR0JMPBUF.xmm6], xmm6
+ movdqa [xDX + VMMR0JMPBUF.xmm7], xmm7
+ movdqa [xDX + VMMR0JMPBUF.xmm8], xmm8
+ movdqa [xDX + VMMR0JMPBUF.xmm9], xmm9
+ movdqa [xDX + VMMR0JMPBUF.xmm10], xmm10
+ movdqa [xDX + VMMR0JMPBUF.xmm11], xmm11
+ movdqa [xDX + VMMR0JMPBUF.xmm12], xmm12
+ movdqa [xDX + VMMR0JMPBUF.xmm13], xmm13
+ movdqa [xDX + VMMR0JMPBUF.xmm14], xmm14
+ movdqa [xDX + VMMR0JMPBUF.xmm15], xmm15
+ %endif
+ pushf
+ pop xAX
+ mov [xDX + VMMR0JMPBUF.rflags], xAX
+
+ ;
+ ; If we're not in a ring-3 call, call pfn and return.
+ ;
+ test byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
+ jnz .resume
+
+ %ifdef VMM_R0_SWITCH_STACK
+ mov r15, [xDX + VMMR0JMPBUF.pvSavedStack]
+ test r15, r15
+ jz .entry_error
+ %ifdef VBOX_STRICT
+ cmp dword [r15], 0h
+ jne .entry_error
+ mov rdi, r15
+ mov rcx, VMM_STACK_SIZE / 8
+ mov rax, qword 0eeeeeeeffeeeeeeeh
+ repne stosq
+ mov [rdi - 10h], rbx
+ %endif
+ lea r15, [r15 + VMM_STACK_SIZE - 40h]
+ mov rsp, r15 ; Switch stack!
+ %endif ; VMM_R0_SWITCH_STACK
+
+ mov r12, rdx ; Save pJmpBuf.
+ %ifdef ASM_CALL64_MSC
+ mov rcx, r8 ; pvUser -> arg0
+ mov rdx, r9
+ %else
+ mov rdi, r8 ; pvUser -> arg0
+ mov rsi, r9
+ %endif
+ call r11
+ mov rdx, r12 ; Restore pJmpBuf
+
+ %ifdef VMM_R0_SWITCH_STACK
+ %ifdef VBOX_STRICT
+ mov r15, [xDX + VMMR0JMPBUF.pvSavedStack]
+ mov dword [r15], 0h ; Reset the marker
+ %endif
+ %endif
+
+ ;
+ ; Return like in the long jump but clear eip, no shortcuts here.
+ ;
+.proper_return:
+%ifdef RT_OS_WINDOWS
+ movdqa xmm6, [xDX + VMMR0JMPBUF.xmm6 ]
+ movdqa xmm7, [xDX + VMMR0JMPBUF.xmm7 ]
+ movdqa xmm8, [xDX + VMMR0JMPBUF.xmm8 ]
+ movdqa xmm9, [xDX + VMMR0JMPBUF.xmm9 ]
+ movdqa xmm10, [xDX + VMMR0JMPBUF.xmm10]
+ movdqa xmm11, [xDX + VMMR0JMPBUF.xmm11]
+ movdqa xmm12, [xDX + VMMR0JMPBUF.xmm12]
+ movdqa xmm13, [xDX + VMMR0JMPBUF.xmm13]
+ movdqa xmm14, [xDX + VMMR0JMPBUF.xmm14]
+ movdqa xmm15, [xDX + VMMR0JMPBUF.xmm15]
+%endif
+ mov rbx, [xDX + VMMR0JMPBUF.rbx]
+%ifdef ASM_CALL64_MSC
+ mov rsi, [xDX + VMMR0JMPBUF.rsi]
+ mov rdi, [xDX + VMMR0JMPBUF.rdi]
+%endif
+ mov r12, [xDX + VMMR0JMPBUF.r12]
+ mov r13, [xDX + VMMR0JMPBUF.r13]
+ mov r14, [xDX + VMMR0JMPBUF.r14]
+ mov r15, [xDX + VMMR0JMPBUF.r15]
+ mov rbp, [xDX + VMMR0JMPBUF.rbp]
+ and qword [xDX + VMMR0JMPBUF.rip], byte 0 ; used for valid check.
+ mov rsp, [xDX + VMMR0JMPBUF.rsp]
+ push qword [xDX + VMMR0JMPBUF.rflags]
+ popf
+ leave
+ ret
+
+.entry_error:
+ mov eax, VERR_VMM_SET_JMP_ERROR
+ jmp .proper_return
+
+.stack_overflow:
+ mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW
+ jmp .proper_return
+
+ ;
+ ; Aborting resume.
+ ; Note! No need to restore XMM registers here since we haven't touched them yet.
+ ;
+.bad:
+ and qword [xDX + VMMR0JMPBUF.rip], byte 0 ; used for valid check.
+ mov rbx, [xDX + VMMR0JMPBUF.rbx]
+ %ifdef ASM_CALL64_MSC
+ mov rsi, [xDX + VMMR0JMPBUF.rsi]
+ mov rdi, [xDX + VMMR0JMPBUF.rdi]
+ %endif
+ mov r12, [xDX + VMMR0JMPBUF.r12]
+ mov r13, [xDX + VMMR0JMPBUF.r13]
+ mov r14, [xDX + VMMR0JMPBUF.r14]
+ mov r15, [xDX + VMMR0JMPBUF.r15]
+ mov eax, VERR_VMM_SET_JMP_ABORTED_RESUME
+ leave
+ ret
+
+ ;
+ ; Resume VMMRZCallRing3 the call.
+ ;
+.resume:
+ %ifndef VMM_R0_SWITCH_STACK
+ ; Sanity checks incoming stack, applying fuzz if needed.
+ sub r10, [xDX + VMMR0JMPBUF.SpCheck]
+ jz .resume_stack_checked_out
+ add r10, STACK_FUZZ_SIZE ; plus/minus STACK_FUZZ_SIZE is fine.
+ cmp r10, STACK_FUZZ_SIZE * 2
+ ja .bad
+
+ mov r10, [xDX + VMMR0JMPBUF.SpCheck]
+ mov [xDX + VMMR0JMPBUF.rsp], r10 ; Must be update in case of another long jump (used for save calc).
+
+.resume_stack_checked_out:
+ mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
+ cmp rcx, VMM_STACK_SIZE
+ ja .bad
+ test rcx, 7
+ jnz .bad
+ mov rdi, [xDX + VMMR0JMPBUF.SpCheck]
+ sub rdi, [xDX + VMMR0JMPBUF.SpResume]
+ cmp rcx, rdi
+ jne .bad
+ %endif
+
+%ifdef VMM_R0_SWITCH_STACK
+ ; Switch stack.
+ mov rsp, [xDX + VMMR0JMPBUF.SpResume]
+%else
+ ; Restore the stack.
+ mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
+ shr ecx, 3
+ mov rsi, [xDX + VMMR0JMPBUF.pvSavedStack]
+ mov rdi, [xDX + VMMR0JMPBUF.SpResume]
+ mov rsp, rdi
+ rep movsq
+%endif ; !VMM_R0_SWITCH_STACK
+ mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 0
+
+ ;
+ ; Continue where we left off.
+ ;
+%ifdef VBOX_STRICT
+ pop rax ; magic
+ cmp rax, RESUME_MAGIC
+ je .magic_ok
+ mov ecx, 0123h
+ mov [ecx], edx
+.magic_ok:
+%endif
+%ifdef RT_OS_WINDOWS
+ movdqa xmm6, [rsp + 000h]
+ movdqa xmm7, [rsp + 010h]
+ movdqa xmm8, [rsp + 020h]
+ movdqa xmm9, [rsp + 030h]
+ movdqa xmm10, [rsp + 040h]
+ movdqa xmm11, [rsp + 050h]
+ movdqa xmm12, [rsp + 060h]
+ movdqa xmm13, [rsp + 070h]
+ movdqa xmm14, [rsp + 080h]
+ movdqa xmm15, [rsp + 090h]
+ add rsp, 0a0h
+%endif
+ popf
+ pop rbx
+%ifdef ASM_CALL64_MSC
+ pop rsi
+ pop rdi
+%endif
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ pop rbp
+ 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 rbp
+ SEH64_PUSH_xBP
+ mov rbp, rsp
+ SEH64_SET_FRAME_xBP 0
+ push r15
+ SEH64_PUSH_GREG r15
+ push r14
+ SEH64_PUSH_GREG r14
+ push r13
+ SEH64_PUSH_GREG r13
+ push r12
+ SEH64_PUSH_GREG r12
+%ifdef ASM_CALL64_MSC
+ push rdi
+ SEH64_PUSH_GREG rdi
+ push rsi
+ SEH64_PUSH_GREG rsi
+%endif
+ push rbx
+ SEH64_PUSH_GREG rbx
+ pushf
+ SEH64_ALLOCATE_STACK 8
+%ifdef RT_OS_WINDOWS
+ sub rsp, 0a0h
+ SEH64_ALLOCATE_STACK 0a0h
+ movdqa [rsp + 000h], xmm6
+ movdqa [rsp + 010h], xmm7
+ movdqa [rsp + 020h], xmm8
+ movdqa [rsp + 030h], xmm9
+ movdqa [rsp + 040h], xmm10
+ movdqa [rsp + 050h], xmm11
+ movdqa [rsp + 060h], xmm12
+ movdqa [rsp + 070h], xmm13
+ movdqa [rsp + 080h], xmm14
+ movdqa [rsp + 090h], xmm15
+%endif
+%ifdef VBOX_STRICT
+ push RESUME_MAGIC
+ SEH64_ALLOCATE_STACK 8
+%endif
+SEH64_END_PROLOGUE
+
+ ;
+ ; Normalize the parameters.
+ ;
+%ifdef ASM_CALL64_MSC
+ mov eax, edx ; rc
+ mov rdx, rcx ; pJmpBuf
+%else
+ mov rdx, rdi ; pJmpBuf
+ mov eax, esi ; rc
+%endif
+
+ ;
+ ; Is the jump buffer armed?
+ ;
+ cmp qword [xDX + VMMR0JMPBUF.rip], byte 0
+ je .nok
+
+ ;
+ ; Sanity checks.
+ ;
+ mov rdi, [xDX + VMMR0JMPBUF.pvSavedStack]
+ test rdi, rdi ; darwin may set this to 0.
+ jz .nok
+ mov [xDX + VMMR0JMPBUF.SpResume], rsp
+ %ifndef VMM_R0_SWITCH_STACK
+ mov rsi, rsp
+ mov rcx, [xDX + VMMR0JMPBUF.rsp]
+ sub rcx, rsi
+
+ ; two sanity checks on the size.
+ cmp rcx, VMM_STACK_SIZE ; check max size.
+ jnbe .nok
+
+ ;
+ ; Copy the stack
+ ;
+ test ecx, 7 ; check alignment
+ jnz .nok
+ mov [xDX + VMMR0JMPBUF.cbSavedStack], ecx
+ shr ecx, 3
+ rep movsq
+
+ %endif ; !VMM_R0_SWITCH_STACK
+
+ ; Save a PC and return PC here to assist unwinding.
+.unwind_point:
+ lea rcx, [.unwind_point wrt RIP]
+ mov [xDX + VMMR0JMPBUF.SavedEipForUnwind], rcx
+ mov rcx, [xDX + VMMR0JMPBUF.rbp]
+ lea rcx, [rcx + 8]
+ mov [xDX + VMMR0JMPBUF.UnwindRetPcLocation], rcx
+ mov rcx, [rcx]
+ mov [xDX + VMMR0JMPBUF.UnwindRetPcValue], rcx
+
+ ; Save RSP & RBP to enable stack dumps
+ mov rcx, rbp
+ mov [xDX + VMMR0JMPBUF.SavedEbp], rcx
+ sub rcx, 8
+ mov [xDX + VMMR0JMPBUF.SavedEsp], rcx
+
+ ; store the last pieces of info.
+ mov rcx, [xDX + VMMR0JMPBUF.rsp]
+ mov [xDX + VMMR0JMPBUF.SpCheck], rcx
+ mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
+
+ ;
+ ; Do the long jump.
+ ;
+%ifdef RT_OS_WINDOWS
+ movdqa xmm6, [xDX + VMMR0JMPBUF.xmm6 ]
+ movdqa xmm7, [xDX + VMMR0JMPBUF.xmm7 ]
+ movdqa xmm8, [xDX + VMMR0JMPBUF.xmm8 ]
+ movdqa xmm9, [xDX + VMMR0JMPBUF.xmm9 ]
+ movdqa xmm10, [xDX + VMMR0JMPBUF.xmm10]
+ movdqa xmm11, [xDX + VMMR0JMPBUF.xmm11]
+ movdqa xmm12, [xDX + VMMR0JMPBUF.xmm12]
+ movdqa xmm13, [xDX + VMMR0JMPBUF.xmm13]
+ movdqa xmm14, [xDX + VMMR0JMPBUF.xmm14]
+ movdqa xmm15, [xDX + VMMR0JMPBUF.xmm15]
+%endif
+ mov rbx, [xDX + VMMR0JMPBUF.rbx]
+%ifdef ASM_CALL64_MSC
+ mov rsi, [xDX + VMMR0JMPBUF.rsi]
+ mov rdi, [xDX + VMMR0JMPBUF.rdi]
+%endif
+ mov r12, [xDX + VMMR0JMPBUF.r12]
+ mov r13, [xDX + VMMR0JMPBUF.r13]
+ mov r14, [xDX + VMMR0JMPBUF.r14]
+ mov r15, [xDX + VMMR0JMPBUF.r15]
+ mov rbp, [xDX + VMMR0JMPBUF.rbp]
+ mov rsp, [xDX + VMMR0JMPBUF.rsp]
+ push qword [xDX + VMMR0JMPBUF.rflags]
+ popf
+ leave
+ ret
+
+ ;
+ ; Failure
+ ;
+.nok:
+%ifdef VBOX_STRICT
+ pop rax ; magic
+ cmp rax, RESUME_MAGIC
+ je .magic_ok
+ mov ecx, 0123h
+ mov [rcx], edx
+.magic_ok:
+%endif
+ mov eax, VERR_VMM_LONG_JMP_ERROR
+%ifdef RT_OS_WINDOWS
+ add rsp, 0a0h ; skip XMM registers since they are unmodified.
+%endif
+ popf
+ pop rbx
+%ifdef ASM_CALL64_MSC
+ pop rsi
+ pop rdi
+%endif
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ leave
+ ret
+ENDPROC vmmR0CallRing3LongJmp
+
+
+;;
+; Internal R0 logger worker: Logger wrapper.
+;
+; @cproto VMMR0DECL(void) vmmR0LoggerWrapper(const char *pszFormat, ...)
+;
+BEGINPROC_EXPORTED vmmR0LoggerWrapper
+SEH64_END_PROLOGUE
+ int3
+ int3
+ int3
+ ret
+ENDPROC vmmR0LoggerWrapper
+