summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac')
-rw-r--r--src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac1297
1 files changed, 1241 insertions, 56 deletions
diff --git a/src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac b/src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac
index f584ade2..44765d6c 100644
--- a/src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac
+++ b/src/VBox/VMM/VMMSwitcher/LegacyandAMD64.mac
@@ -1,8 +1,14 @@
-; VMM - World Switchers, 32Bit to AMD64.
+; $Id: LegacyandAMD64.mac $
+;; @file
+; VMM - World Switchers, 32-bit to AMD64 intermediate context.
+;
+; This is used for running 64-bit guest on 32-bit hosts, not
+; normal raw-mode. All the code involved is contained in this
+; file.
;
;
-; Copyright (C) 2006-2012 Oracle Corporation
+; Copyright (C) 2006-2013 Oracle Corporation
;
; This file is part of VirtualBox Open Source Edition (OSE), as
; available from http://www.virtualbox.org. This file is free software;
@@ -13,24 +19,99 @@
; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
;
-;%define DEBUG_STUFF 1
-;%define STRICT_IF 1
;*******************************************************************************
;* Defined Constants And Macros *
;*******************************************************************************
+;; @note These values are from the HM64ON32OP enum in hm.h.
+%define HM64ON32OP_VMXRCStartVM64 1
+%define HM64ON32OP_SVMRCVMRun64 2
+%define HM64ON32OP_HMRCSaveGuestFPU64 3
+%define HM64ON32OP_HMRCSaveGuestDebug64 4
+%define HM64ON32OP_HMRCTestSwitcher64 5
+
+;;
+; This macro is used for storing a debug code in a CMOS location.
+;
+; If we tripple fault or something, the debug code can be retrieved and we
+; might have a clue as to where the problem occurred. The code is currently
+; using CMOS register 3 in the 2nd bank as this _seems_ to be unused on my
+; Extreme4 X79 asrock mainboard.
+;
+; @param %1 The debug code (byte)
+; @note Trashes AL.
+;
+%macro DEBUG_CMOS_TRASH_AL 1
+%ifdef VBOX_WITH_64ON32_CMOS_DEBUG
+ mov al, 3
+ out 72h, al
+ mov al, %1
+ out 73h, al
+ in al, 73h
+%endif
+%endmacro
+
+;;
+; Version of DEBUG_CMOS_TRASH_AL that saves AL on the stack and therefore
+; doesn't trash any registers.
+;
+%macro DEBUG_CMOS_STACK64 1
+%ifdef VBOX_WITH_64ON32_CMOS_DEBUG
+ push rax
+ DEBUG_CMOS_TRASH_AL %1
+ pop rax
+%endif
+%endmacro
+
+;;
+; Version of DEBUG_CMOS_TRASH_AL that saves AL on the stack and therefore
+; doesn't trash any registers.
+;
+%macro DEBUG_CMOS_STACK32 1
+%ifdef VBOX_WITH_64ON32_CMOS_DEBUG
+ push eax
+ DEBUG_CMOS_TRASH_AL %1
+ pop eax
+%endif
+%endmacro
+
+
+;; Stubs for making OS/2 compile (though, not work).
+%ifdef RT_OS_OS2 ;; @todo fix OMF support in yasm and kick nasm out completely.
+ %macro vmwrite 2,
+ int3
+ %endmacro
+ %define vmlaunch int3
+ %define vmresume int3
+ %define vmsave int3
+ %define vmload int3
+ %define vmrun int3
+ %define clgi int3
+ %define stgi int3
+ %macro invlpga 2,
+ int3
+ %endmacro
+%endif
+
+;; Debug options
+;%define DEBUG_STUFF 1
+;%define STRICT_IF 1
;*******************************************************************************
;* Header Files *
;*******************************************************************************
%include "VBox/asmdefs.mac"
-%include "VBox/apic.mac"
%include "iprt/x86.mac"
+%include "VBox/err.mac"
+%include "VBox/apic.mac"
+
%include "VBox/vmm/cpum.mac"
%include "VBox/vmm/stam.mac"
%include "VBox/vmm/vm.mac"
+%include "VBox/vmm/hm_vmx.mac"
%include "CPUMInternal.mac"
+%include "HMInternal.mac"
%include "VMMSwitcher.mac"
@@ -53,7 +134,8 @@ BITS 32
;;
; The C interface.
; @param [esp + 04h] Param 1 - VM handle
-; @param [esp + 08h] Param 2 - VMCPU offset
+; @param [esp + 08h] Param 2 - Offset from VM::CPUM to the CPUMCPU
+; structure for the calling EMT.
;
BEGINPROC vmmR0ToRawMode
%ifdef DEBUG_STUFF
@@ -71,11 +153,12 @@ BEGINPROC vmmR0ToRawMode
%endif
push ebp
- mov ebp, [esp + 12] ; VMCPU offset
+ mov ebp, [esp + 12] ; CPUMCPU offset
; turn off interrupts
pushf
cli
+ ;DEBUG_CMOS_STACK32 10h
;
; Call worker.
@@ -86,10 +169,15 @@ BEGINPROC vmmR0ToRawMode
call NAME(vmmR0ToRawModeAsm)
%ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
- CPUM_FROM_CPUMCPU(edx)
; Restore blocked Local APIC NMI vectors
- mov ecx, [edx + CPUM.fApicDisVectors]
- mov edx, [edx + CPUM.pvApicBase]
+ ; Do this here to ensure the host CS is already restored
+ mov ecx, [edx + CPUMCPU.fApicDisVectors]
+ test ecx, ecx
+ jz gth_apic_done
+ cmp byte [edx + CPUMCPU.fX2Apic], 1
+ je gth_x2apic
+
+ mov edx, [edx + CPUMCPU.pvApicBase]
shr ecx, 1
jnc gth_nolint0
and dword [edx + APIC_REG_LVT_LINT0], ~APIC_REG_LVT_MASKED
@@ -106,9 +194,51 @@ gth_nopc:
jnc gth_notherm
and dword [edx + APIC_REG_LVT_THMR], ~APIC_REG_LVT_MASKED
gth_notherm:
+ jmp gth_apic_done
+
+gth_x2apic:
+ ;DEBUG_CMOS_STACK32 7ch
+ push eax ; save eax
+ push ebx ; save it for fApicDisVectors
+ push edx ; save edx just in case.
+ mov ebx, ecx ; ebx = fApicDisVectors, ecx free for MSR use
+ shr ebx, 1
+ jnc gth_x2_nolint0
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_LINT0 >> 4)
+ rdmsr
+ and eax, ~APIC_REG_LVT_MASKED
+ wrmsr
+gth_x2_nolint0:
+ shr ebx, 1
+ jnc gth_x2_nolint1
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_LINT1 >> 4)
+ rdmsr
+ and eax, ~APIC_REG_LVT_MASKED
+ wrmsr
+gth_x2_nolint1:
+ shr ebx, 1
+ jnc gth_x2_nopc
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_PC >> 4)
+ rdmsr
+ and eax, ~APIC_REG_LVT_MASKED
+ wrmsr
+gth_x2_nopc:
+ shr ebx, 1
+ jnc gth_x2_notherm
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_THMR >> 4)
+ rdmsr
+ and eax, ~APIC_REG_LVT_MASKED
+ wrmsr
+gth_x2_notherm:
+ pop edx
+ pop ebx
+ pop eax
+
+gth_apic_done:
%endif
; restore original flags
+ ;DEBUG_CMOS_STACK32 7eh
popf
pop ebp
@@ -121,6 +251,7 @@ gth_notherm:
STAM_PROFILE_ADV_STOP edx
%endif
+ ;DEBUG_CMOS_STACK32 7fh
ret
ENDPROC vmmR0ToRawMode
@@ -132,7 +263,7 @@ ENDPROC vmmR0ToRawMode
;
; INPUT:
; - edx virtual address of CPUM structure (valid in host context)
-; - ebp offset of the CPUMCPU structure
+; - ebp offset of the CPUMCPU structure relative to CPUM.
;
; USES/DESTROYS:
; - eax, ecx, edx, esi
@@ -161,7 +292,7 @@ BEGINPROC vmmR0ToRawModeAsm
mov [edx + CPUMCPU.Host.edi], edi
mov [edx + CPUMCPU.Host.esi], esi
mov [edx + CPUMCPU.Host.esp], esp
- mov [edx + CPUMCPU.Host.ebp], ebp
+ mov [edx + CPUMCPU.Host.ebp], ebp ; offCpumCpu!
; selectors.
mov [edx + CPUMCPU.Host.ds], ds
mov [edx + CPUMCPU.Host.es], es
@@ -169,6 +300,8 @@ BEGINPROC vmmR0ToRawModeAsm
mov [edx + CPUMCPU.Host.gs], gs
mov [edx + CPUMCPU.Host.ss], ss
; special registers.
+ DEBUG32_S_CHAR('s')
+ DEBUG32_S_CHAR(';')
sldt [edx + CPUMCPU.Host.ldtr]
sidt [edx + CPUMCPU.Host.idtr]
sgdt [edx + CPUMCPU.Host.gdtr]
@@ -179,10 +312,14 @@ BEGINPROC vmmR0ToRawModeAsm
%endif
%ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
- CPUM_FROM_CPUMCPU_WITH_OFFSET edx, ebp
- mov ebx, [edx + CPUM.pvApicBase]
+ DEBUG32_S_CHAR('f')
+ DEBUG32_S_CHAR(';')
+ cmp byte [edx + CPUMCPU.pvApicBase], 1
+ je htg_x2apic
+
+ mov ebx, [edx + CPUMCPU.pvApicBase]
or ebx, ebx
- jz htg_noapic
+ jz htg_apic_done
mov eax, [ebx + APIC_REG_LVT_LINT0]
mov ecx, eax
and ecx, (APIC_REG_LVT_MASKED | APIC_REG_LVT_MODE_MASK)
@@ -227,9 +364,62 @@ htg_nopc:
mov [ebx + APIC_REG_LVT_THMR], eax
mov eax, [ebx + APIC_REG_LVT_THMR] ; write completion
htg_notherm:
- mov [edx + CPUM.fApicDisVectors], edi
-htg_noapic:
- CPUMCPU_FROM_CPUM_WITH_OFFSET edx, ebp
+ mov [edx + CPUMCPU.fApicDisVectors], edi
+ jmp htg_apic_done
+
+htg_x2apic:
+ mov esi, edx ; Save edx.
+ xor edi, edi ; fApicDisVectors
+
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_LINT0 >> 4)
+ rdmsr
+ mov ebx, eax
+ and ebx, (APIC_REG_LVT_MASKED | APIC_REG_LVT_MODE_MASK)
+ cmp ebx, APIC_REG_LVT_MODE_NMI
+ jne htg_x2_nolint0
+ or edi, 0x01
+ or eax, APIC_REG_LVT_MASKED
+ wrmsr
+htg_x2_nolint0:
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_LINT1 >> 4)
+ rdmsr
+ mov ebx, eax
+ and ebx, (APIC_REG_LVT_MASKED | APIC_REG_LVT_MODE_MASK)
+ cmp ebx, APIC_REG_LVT_MODE_NMI
+ jne htg_x2_nolint1
+ or edi, 0x02
+ or eax, APIC_REG_LVT_MASKED
+ wrmsr
+htg_x2_nolint1:
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_PC >> 4)
+ rdmsr
+ mov ebx, eax
+ and ebx, (APIC_REG_LVT_MASKED | APIC_REG_LVT_MODE_MASK)
+ cmp ebx, APIC_REG_LVT_MODE_NMI
+ jne htg_x2_nopc
+ or edi, 0x04
+ or eax, APIC_REG_LVT_MASKED
+ wrmsr
+htg_x2_nopc:
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_VERSION >> 4)
+ rdmsr
+ shr eax, 16
+ cmp al, 5
+ jb htg_x2_notherm
+ mov ecx, MSR_IA32_X2APIC_START + (APIC_REG_LVT_THMR >> 4)
+ rdmsr
+ mov ebx, eax
+ and ebx, (APIC_REG_LVT_MASKED | APIC_REG_LVT_MODE_MASK)
+ cmp ebx, APIC_REG_LVT_MODE_NMI
+ jne htg_x2_notherm
+ or edi, 0x08
+ or eax, APIC_REG_LVT_MASKED
+ wrmsr
+htg_x2_notherm:
+ mov edx, esi ; Restore edx.
+ mov [edx + CPUMCPU.fApicDisVectors], edi
+
+htg_apic_done:
%endif
; control registers.
@@ -238,8 +428,11 @@ htg_noapic:
;Skip cr2; assume host os don't stuff things in cr2. (safe)
mov eax, cr3
mov [edx + CPUMCPU.Host.cr3], eax
- mov eax, cr4
- mov [edx + CPUMCPU.Host.cr4], eax
+ mov esi, cr4 ; esi = cr4, we'll modify it further down.
+ mov [edx + CPUMCPU.Host.cr4], esi
+
+ DEBUG32_S_CHAR('c')
+ DEBUG32_S_CHAR(';')
; save the host EFER msr
mov ebx, edx
@@ -248,25 +441,41 @@ htg_noapic:
mov [ebx + CPUMCPU.Host.efer], eax
mov [ebx + CPUMCPU.Host.efer + 4], edx
mov edx, ebx
+ DEBUG32_S_CHAR('e')
+ DEBUG32_S_CHAR(';')
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov dword [edx + CPUMCPU.Guest.dr + 4*8], 3
%endif
; Load new gdt so we can do a far jump after going into 64 bits mode
+ ;DEBUG_CMOS_STACK32 16h
lgdt [edx + CPUMCPU.Hyper.gdtr]
+ DEBUG32_S_CHAR('g')
+ DEBUG32_S_CHAR('!')
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov dword [edx + CPUMCPU.Guest.dr + 4*8], 4
%endif
;;
+ ;; Clean up CR4. X86_CR4_PGE, X86_CR4_PCE, X86_CR4_PCIDE (not really
+ ;; relevant for 32-bit, but whatever) and X86_CR4_VMXE must be cleared.
+ ;;
+ and esi, X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE | X86_CR4_PSE | X86_CR4_PAE \
+ | X86_CR4_MCE | X86_CR4_OSFSXR | X86_CR4_OSXMMEEXCPT | X86_CR4_SMXE | X86_CR4_OSXSAVE
+ mov cr4, esi
+
+ ;;
;; Load Intermediate memory context.
;;
FIXUP SWITCHER_FIX_INTER_CR3_HC, 1
mov eax, 0ffffffffh
mov cr3, eax
- DEBUG_CHAR('?')
+ DEBUG32_CHAR('?')
+%ifdef VBOX_WITH_64ON32_CMOS_DEBUG
+ DEBUG_CMOS_TRASH_AL 17h
+%endif
;;
;; Jump to identity mapped location
@@ -278,13 +487,15 @@ htg_noapic:
; We're now on identity mapped pages!
ALIGNCODE(16)
GLOBALNAME IDEnterTarget
- DEBUG_CHAR('2')
+ DEBUG32_CHAR('1')
+ DEBUG_CMOS_TRASH_AL 19h
; 1. Disable paging.
mov ebx, cr0
and ebx, ~X86_CR0_PG
mov cr0, ebx
- DEBUG_CHAR('2')
+ DEBUG32_CHAR('2')
+ DEBUG_CMOS_TRASH_AL 1ah
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov eax, cr2
@@ -295,12 +506,14 @@ GLOBALNAME IDEnterTarget
mov ecx, cr4
or ecx, X86_CR4_PAE
mov cr4, ecx
+ DEBUG_CMOS_TRASH_AL 1bh
; 3. Load long mode intermediate CR3.
FIXUP FIX_INTER_AMD64_CR3, 1
mov ecx, 0ffffffffh
mov cr3, ecx
- DEBUG_CHAR('3')
+ DEBUG32_CHAR('3')
+ DEBUG_CMOS_TRASH_AL 1ch
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov eax, cr2
@@ -316,7 +529,8 @@ GLOBALNAME IDEnterTarget
and eax, ~(MSR_K6_EFER_FFXSR) ; turn off fast fxsave/fxrstor (skipping xmm regs)
wrmsr
mov edx, esi
- DEBUG_CHAR('4')
+ DEBUG32_CHAR('4')
+ DEBUG_CMOS_TRASH_AL 1dh
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov eax, cr2
@@ -328,7 +542,7 @@ GLOBALNAME IDEnterTarget
; Disable ring 0 write protection too
and ebx, ~X86_CR0_WRITE_PROTECT
mov cr0, ebx
- DEBUG_CHAR('5')
+ DEBUG32_CHAR('5')
; Jump from compatibility mode to 64-bit mode.
FIXUP FIX_ID_FAR32_TO_64BIT_MODE, 1, NAME(IDEnter64Mode) - NAME(Start)
@@ -339,7 +553,8 @@ GLOBALNAME IDEnterTarget
BITS 64
ALIGNCODE(16)
NAME(IDEnter64Mode):
- DEBUG_CHAR('6')
+ DEBUG64_CHAR('6')
+ DEBUG_CMOS_TRASH_AL 1eh
jmp [NAME(pICEnterTarget) wrt rip]
; 64-bit jump target
@@ -362,6 +577,7 @@ db 'Switch_marker'
;
ALIGNCODE(16)
GLOBALNAME ICEnterTarget
+ ;DEBUG_CMOS_TRASH_AL 1fh
; Load CPUM pointer into rdx
mov rdx, [NAME(pCpumIC) wrt rip]
CPUMCPU_FROM_CPUM_WITH_OFFSET edx, ebp
@@ -380,7 +596,7 @@ GLOBALNAME ICEnterTarget
%endif
; Setup stack.
- DEBUG_CHAR('7')
+ DEBUG64_CHAR('7')
mov rsp, 0
mov eax, [rdx + CPUMCPU.Hyper.ss.Sel]
mov ss, ax
@@ -390,14 +606,19 @@ GLOBALNAME ICEnterTarget
mov dword [rdx + CPUMCPU.Guest.dr + 4*8], 6
%endif
+%ifdef VBOX_WITH_64ON32_IDT
+ ; Set up emergency trap handlers.
+ lidt [rdx + CPUMCPU.Hyper.idtr]
+%endif
; load the hypervisor function address
mov r9, [rdx + CPUMCPU.Hyper.eip]
+ DEBUG64_S_CHAR('8')
; Check if we need to restore the guest FPU state
mov esi, [rdx + CPUMCPU.fUseFlags] ; esi == use flags.
test esi, CPUM_SYNC_FPU_STATE
- jz near gth_fpu_no
+ jz near htg_fpu_no
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov dword [rdx + CPUMCPU.Guest.dr + 4*8], 7
@@ -407,20 +628,24 @@ GLOBALNAME ICEnterTarget
mov rcx, rax ; save old CR0
and rax, ~(X86_CR0_TS | X86_CR0_EM)
mov cr0, rax
- fxrstor [rdx + CPUMCPU.Guest.fpu]
+ ; Use explicit REX prefix. See @bugref{6398}.
+ o64 fxrstor [rdx + CPUMCPU.Guest.fpu]
mov cr0, rcx ; and restore old CR0 again
and dword [rdx + CPUMCPU.fUseFlags], ~CPUM_SYNC_FPU_STATE
-gth_fpu_no:
+htg_fpu_no:
; Check if we need to restore the guest debug state
- test esi, CPUM_SYNC_DEBUG_STATE
- jz near gth_debug_no
+ test esi, CPUM_SYNC_DEBUG_REGS_GUEST | CPUM_SYNC_DEBUG_REGS_HYPER
+ jz htg_debug_done
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov dword [rdx + CPUMCPU.Guest.dr + 4*8], 8
%endif
+ test esi, CPUM_SYNC_DEBUG_REGS_HYPER
+ jnz htg_debug_hyper
+ ; Guest values in DRx, letting the guest access them directly.
mov rax, qword [rdx + CPUMCPU.Guest.dr + 0*8]
mov dr0, rax
mov rax, qword [rdx + CPUMCPU.Guest.dr + 1*8]
@@ -432,17 +657,55 @@ gth_fpu_no:
mov rax, qword [rdx + CPUMCPU.Guest.dr + 6*8]
mov dr6, rax ; not required for AMD-V
- and dword [rdx + CPUMCPU.fUseFlags], ~CPUM_SYNC_DEBUG_STATE
+ and dword [rdx + CPUMCPU.fUseFlags], ~CPUM_SYNC_DEBUG_REGS_GUEST
+ or dword [rdx + CPUMCPU.fUseFlags], CPUM_USED_DEBUG_REGS_GUEST
+ jmp htg_debug_done
-gth_debug_no:
+htg_debug_hyper:
+ ; Combined values in DRx, intercepting all accesses.
+ mov rax, qword [rdx + CPUMCPU.Hyper.dr + 0*8]
+ mov dr0, rax
+ mov rax, qword [rdx + CPUMCPU.Hyper.dr + 1*8]
+ mov dr1, rax
+ mov rax, qword [rdx + CPUMCPU.Hyper.dr + 2*8]
+ mov dr2, rax
+ mov rax, qword [rdx + CPUMCPU.Hyper.dr + 3*8]
+ mov dr3, rax
+ mov rax, qword [rdx + CPUMCPU.Hyper.dr + 6*8]
+ mov dr6, rax ; not required for AMD-V
+
+ and dword [rdx + CPUMCPU.fUseFlags], ~CPUM_SYNC_DEBUG_REGS_HYPER
+ or dword [rdx + CPUMCPU.fUseFlags], CPUM_USED_DEBUG_REGS_HYPER
+
+htg_debug_done:
%ifdef VBOX_WITH_CRASHDUMP_MAGIC
mov dword [rdx + CPUMCPU.Guest.dr + 4*8], 9
%endif
+ ;
+ ; "Call" the specified helper function.
+ ;
+
; parameter for all helper functions (pCtx)
+ DEBUG64_CHAR('9')
lea rsi, [rdx + CPUMCPU.Guest.fpu]
- call r9
+ lea rax, [htg_return wrt rip]
+ push rax ; return address
+
+ cmp r9d, HM64ON32OP_VMXRCStartVM64
+ jz NAME(VMXRCStartVM64)
+ cmp r9d, HM64ON32OP_SVMRCVMRun64
+ jz NAME(SVMRCVMRun64)
+ cmp r9d, HM64ON32OP_HMRCSaveGuestFPU64
+ jz NAME(HMRCSaveGuestFPU64)
+ cmp r9d, HM64ON32OP_HMRCSaveGuestDebug64
+ jz NAME(HMRCSaveGuestDebug64)
+ cmp r9d, HM64ON32OP_HMRCTestSwitcher64
+ jz NAME(HMRCTestSwitcher64)
+ mov eax, VERR_HM_INVALID_HM64ON32OP
+htg_return:
+ DEBUG64_CHAR('r')
; Load CPUM pointer into rdx
mov rdx, [NAME(pCpumIC) wrt rip]
@@ -461,6 +724,915 @@ gth_debug_no:
ENDPROC vmmR0ToRawModeAsm
+
+
+;
+;
+; HM code (used to be HMRCA.asm at one point).
+; HM code (used to be HMRCA.asm at one point).
+; HM code (used to be HMRCA.asm at one point).
+;
+;
+
+
+
+; Load the corresponding guest MSR (trashes rdx & rcx)
+%macro LOADGUESTMSR 2
+ mov rcx, %1
+ mov edx, dword [rsi + %2 + 4]
+ mov eax, dword [rsi + %2]
+ wrmsr
+%endmacro
+
+; Save a guest MSR (trashes rdx & rcx)
+; Only really useful for gs kernel base as that one can be changed behind our back (swapgs)
+%macro SAVEGUESTMSR 2
+ mov rcx, %1
+ rdmsr
+ mov dword [rsi + %2], eax
+ mov dword [rsi + %2 + 4], edx
+%endmacro
+
+;; @def MYPUSHSEGS
+; Macro saving all segment registers on the stack.
+; @param 1 full width register name
+%macro MYPUSHSEGS 1
+ mov %1, es
+ push %1
+ mov %1, ds
+ push %1
+%endmacro
+
+;; @def MYPOPSEGS
+; Macro restoring all segment registers on the stack
+; @param 1 full width register name
+%macro MYPOPSEGS 1
+ pop %1
+ mov ds, %1
+ pop %1
+ mov es, %1
+%endmacro
+
+
+;/**
+; * Prepares for and executes VMLAUNCH/VMRESUME (64 bits guest mode)
+; *
+; * @returns VBox status code
+; * @param HCPhysCpuPage VMXON physical address [rsp+8]
+; * @param HCPhysVmcs VMCS physical address [rsp+16]
+; * @param pCache VMCS cache [rsp+24]
+; * @param pCtx Guest context (rsi)
+; */
+BEGINPROC VMXRCStartVM64
+ push rbp
+ mov rbp, rsp
+ DEBUG_CMOS_STACK64 20h
+
+ ; Make sure VT-x instructions are allowed.
+ mov rax, cr4
+ or rax, X86_CR4_VMXE
+ mov cr4, rax
+
+ ; Enter VMX Root Mode.
+ vmxon [rbp + 8 + 8]
+ jnc .vmxon_success
+ mov rax, VERR_VMX_INVALID_VMXON_PTR
+ jmp .vmstart64_vmxon_failed
+
+.vmxon_success:
+ jnz .vmxon_success2
+ mov rax, VERR_VMX_VMXON_FAILED
+ jmp .vmstart64_vmxon_failed
+
+.vmxon_success2:
+ ; Activate the VMCS pointer
+ vmptrld [rbp + 16 + 8]
+ jnc .vmptrld_success
+ mov rax, VERR_VMX_INVALID_VMCS_PTR
+ jmp .vmstart64_vmxoff_end
+
+.vmptrld_success:
+ jnz .vmptrld_success2
+ mov rax, VERR_VMX_VMPTRLD_FAILED
+ jmp .vmstart64_vmxoff_end
+
+.vmptrld_success2:
+
+ ; Save the VMCS pointer on the stack
+ push qword [rbp + 16 + 8];
+
+ ; Save segment registers.
+ MYPUSHSEGS rax
+
+%ifdef VMX_USE_CACHED_VMCS_ACCESSES
+ ; Flush the VMCS write cache first (before any other vmreads/vmwrites!).
+ mov rbx, [rbp + 24 + 8] ; pCache
+
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov qword [rbx + VMCSCACHE.uPos], 2
+ %endif
+
+ %ifdef DEBUG
+ mov rax, [rbp + 8 + 8] ; HCPhysCpuPage
+ mov [rbx + VMCSCACHE.TestIn.HCPhysCpuPage], rax
+ mov rax, [rbp + 16 + 8] ; HCPhysVmcs
+ mov [rbx + VMCSCACHE.TestIn.HCPhysVmcs], rax
+ mov [rbx + VMCSCACHE.TestIn.pCache], rbx
+ mov [rbx + VMCSCACHE.TestIn.pCtx], rsi
+ %endif
+
+ mov ecx, [rbx + VMCSCACHE.Write.cValidEntries]
+ cmp ecx, 0
+ je .no_cached_writes
+ mov rdx, rcx
+ mov rcx, 0
+ jmp .cached_write
+
+ALIGN(16)
+.cached_write:
+ mov eax, [rbx + VMCSCACHE.Write.aField + rcx*4]
+ vmwrite rax, qword [rbx + VMCSCACHE.Write.aFieldVal + rcx*8]
+ inc rcx
+ cmp rcx, rdx
+ jl .cached_write
+
+ mov dword [rbx + VMCSCACHE.Write.cValidEntries], 0
+.no_cached_writes:
+
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov qword [rbx + VMCSCACHE.uPos], 3
+ %endif
+ ; Save the pCache pointer.
+ push rbx
+%endif
+
+ ; Save the host state that's relevant in the temporary 64-bit mode.
+ mov rdx, cr0
+ mov eax, VMX_VMCS_HOST_CR0
+ vmwrite rax, rdx
+
+ mov rdx, cr3
+ mov eax, VMX_VMCS_HOST_CR3
+ vmwrite rax, rdx
+
+ mov rdx, cr4
+ mov eax, VMX_VMCS_HOST_CR4
+ vmwrite rax, rdx
+
+ mov rdx, cs
+ mov eax, VMX_VMCS_HOST_FIELD_CS
+ vmwrite rax, rdx
+
+ mov rdx, ss
+ mov eax, VMX_VMCS_HOST_FIELD_SS
+ vmwrite rax, rdx
+
+%if 0 ; Another experiment regarding tripple faults... Seems not to be necessary.
+ sub rsp, 16
+ str [rsp]
+ movsx rdx, word [rsp]
+ mov eax, VMX_VMCS_HOST_FIELD_TR
+ vmwrite rax, rdx
+ add rsp, 16
+%endif
+
+ sub rsp, 16
+ sgdt [rsp + 6] ; (The 64-bit base should be aligned, not the word.)
+ mov eax, VMX_VMCS_HOST_GDTR_BASE
+ vmwrite rax, [rsp + 6 + 2]
+ add rsp, 16
+
+%ifdef VBOX_WITH_64ON32_IDT
+ sub rsp, 16
+ sidt [rsp + 6]
+ mov eax, VMX_VMCS_HOST_IDTR_BASE
+ vmwrite rax, [rsp + 6 + 2] ; [rsi + CPUMCPU.Hyper.idtr + 2] - why doesn't this work?
+ add rsp, 16
+ ;call NAME(vmm64On32PrintIdtr)
+%endif
+
+%ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov qword [rbx + VMCSCACHE.uPos], 4
+%endif
+
+ ; Hopefully we can ignore TR (we restore it anyway on the way back to 32-bit mode).
+
+ ; First we have to save some final CPU context registers.
+ lea rdx, [.vmlaunch64_done wrt rip]
+ mov rax, VMX_VMCS_HOST_RIP ; Return address (too difficult to continue after VMLAUNCH?).
+ vmwrite rax, rdx
+ ; Note: assumes success!
+
+ ; Manual save and restore:
+ ; - General purpose registers except RIP, RSP
+ ;
+ ; Trashed:
+ ; - CR2 (we don't care)
+ ; - LDTR (reset to 0)
+ ; - DRx (presumably not changed at all)
+ ; - DR7 (reset to 0x400)
+ ; - EFLAGS (reset to RT_BIT(1); not relevant)
+
+%ifndef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
+ ; Load the guest LSTAR, CSTAR, SFMASK & KERNEL_GSBASE MSRs.
+ LOADGUESTMSR MSR_K8_LSTAR, CPUMCTX.msrLSTAR
+ LOADGUESTMSR MSR_K6_STAR, CPUMCTX.msrSTAR
+ LOADGUESTMSR MSR_K8_SF_MASK, CPUMCTX.msrSFMASK
+ LOADGUESTMSR MSR_K8_KERNEL_GS_BASE, CPUMCTX.msrKERNELGSBASE
+%endif
+
+%ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov qword [rbx + VMCSCACHE.uPos], 5
+%endif
+
+ ; Save the pCtx pointer
+ push rsi
+
+ ; Load CR2 if necessary (may be expensive as writing CR2 is a synchronizing instruction).
+ mov rbx, qword [rsi + CPUMCTX.cr2]
+ mov rdx, cr2
+ cmp rdx, rbx
+ je .skipcr2write64
+ mov cr2, rbx
+
+.skipcr2write64:
+ mov eax, VMX_VMCS_HOST_RSP
+ vmwrite rax, rsp
+ ; Note: assumes success!
+ ; Don't mess with ESP anymore!!!
+
+ ; Save Guest's general purpose registers.
+ mov rax, qword [rsi + CPUMCTX.eax]
+ mov rbx, qword [rsi + CPUMCTX.ebx]
+ mov rcx, qword [rsi + CPUMCTX.ecx]
+ mov rdx, qword [rsi + CPUMCTX.edx]
+ mov rbp, qword [rsi + CPUMCTX.ebp]
+ mov r8, qword [rsi + CPUMCTX.r8]
+ mov r9, qword [rsi + CPUMCTX.r9]
+ mov r10, qword [rsi + CPUMCTX.r10]
+ mov r11, qword [rsi + CPUMCTX.r11]
+ mov r12, qword [rsi + CPUMCTX.r12]
+ mov r13, qword [rsi + CPUMCTX.r13]
+ mov r14, qword [rsi + CPUMCTX.r14]
+ mov r15, qword [rsi + CPUMCTX.r15]
+
+ ; Save rdi & rsi.
+ mov rdi, qword [rsi + CPUMCTX.edi]
+ mov rsi, qword [rsi + CPUMCTX.esi]
+
+ vmlaunch
+ jmp .vmlaunch64_done; ; Here if vmlaunch detected a failure.
+
+ALIGNCODE(16)
+.vmlaunch64_done:
+%if 0 ;fixme later - def VBOX_WITH_64ON32_IDT
+ push rdx
+ mov rdx, [rsp + 8] ; pCtx
+ lidt [rdx + CPUMCPU.Hyper.idtr]
+ pop rdx
+%endif
+ jc near .vmstart64_invalid_vmcs_ptr
+ jz near .vmstart64_start_failed
+
+ push rdi
+ mov rdi, [rsp + 8] ; pCtx
+
+ mov qword [rdi + CPUMCTX.eax], rax
+ mov qword [rdi + CPUMCTX.ebx], rbx
+ mov qword [rdi + CPUMCTX.ecx], rcx
+ mov qword [rdi + CPUMCTX.edx], rdx
+ mov qword [rdi + CPUMCTX.esi], rsi
+ mov qword [rdi + CPUMCTX.ebp], rbp
+ mov qword [rdi + CPUMCTX.r8], r8
+ mov qword [rdi + CPUMCTX.r9], r9
+ mov qword [rdi + CPUMCTX.r10], r10
+ mov qword [rdi + CPUMCTX.r11], r11
+ mov qword [rdi + CPUMCTX.r12], r12
+ mov qword [rdi + CPUMCTX.r13], r13
+ mov qword [rdi + CPUMCTX.r14], r14
+ mov qword [rdi + CPUMCTX.r15], r15
+ mov rax, cr2
+ mov qword [rdi + CPUMCTX.cr2], rax
+
+ pop rax ; The guest edi we pushed above
+ mov qword [rdi + CPUMCTX.edi], rax
+
+ pop rsi ; pCtx (needed in rsi by the macros below)
+
+%ifndef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
+ SAVEGUESTMSR MSR_K8_KERNEL_GS_BASE, CPUMCTX.msrKERNELGSBASE
+ SAVEGUESTMSR MSR_K8_SF_MASK, CPUMCTX.msrSFMASK
+ SAVEGUESTMSR MSR_K6_STAR, CPUMCTX.msrSTAR
+ SAVEGUESTMSR MSR_K8_LSTAR, CPUMCTX.msrLSTAR
+%endif
+
+%ifdef VMX_USE_CACHED_VMCS_ACCESSES
+ pop rdi ; Saved pCache
+
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov dword [rdi + VMCSCACHE.uPos], 7
+ %endif
+ %ifdef DEBUG
+ mov [rdi + VMCSCACHE.TestOut.pCache], rdi
+ mov [rdi + VMCSCACHE.TestOut.pCtx], rsi
+ mov rax, cr8
+ mov [rdi + VMCSCACHE.TestOut.cr8], rax
+ %endif
+
+ mov ecx, [rdi + VMCSCACHE.Read.cValidEntries]
+ cmp ecx, 0 ; Can't happen
+ je .no_cached_reads
+ jmp .cached_read
+
+ALIGN(16)
+.cached_read:
+ dec rcx
+ mov eax, [rdi + VMCSCACHE.Read.aField + rcx*4]
+ vmread qword [rdi + VMCSCACHE.Read.aFieldVal + rcx*8], rax
+ cmp rcx, 0
+ jnz .cached_read
+.no_cached_reads:
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov dword [rdi + VMCSCACHE.uPos], 8
+ %endif
+%endif
+
+ ; Restore segment registers.
+ MYPOPSEGS rax
+
+ mov eax, VINF_SUCCESS
+
+%ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov dword [rdi + VMCSCACHE.uPos], 9
+%endif
+.vmstart64_end:
+
+%ifdef VMX_USE_CACHED_VMCS_ACCESSES
+ %ifdef DEBUG
+ mov rdx, [rsp] ; HCPhysVmcs
+ mov [rdi + VMCSCACHE.TestOut.HCPhysVmcs], rdx
+ %endif
+%endif
+
+ ; Write back the data and disable the VMCS.
+ vmclear qword [rsp] ; Pushed pVMCS
+ add rsp, 8
+
+.vmstart64_vmxoff_end:
+ ; Disable VMX root mode.
+ vmxoff
+.vmstart64_vmxon_failed:
+%ifdef VMX_USE_CACHED_VMCS_ACCESSES
+ %ifdef DEBUG
+ cmp eax, VINF_SUCCESS
+ jne .skip_flags_save
+
+ pushf
+ pop rdx
+ mov [rdi + VMCSCACHE.TestOut.eflags], rdx
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov dword [rdi + VMCSCACHE.uPos], 12
+ %endif
+.skip_flags_save:
+ %endif
+%endif
+ pop rbp
+ ret
+
+
+.vmstart64_invalid_vmcs_ptr:
+ pop rsi ; pCtx (needed in rsi by the macros below)
+
+%ifdef VMX_USE_CACHED_VMCS_ACCESSES
+ pop rdi ; pCache
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov dword [rdi + VMCSCACHE.uPos], 10
+ %endif
+
+ %ifdef DEBUG
+ mov [rdi + VMCSCACHE.TestOut.pCache], rdi
+ mov [rdi + VMCSCACHE.TestOut.pCtx], rsi
+ %endif
+%endif
+
+ ; Restore segment registers.
+ MYPOPSEGS rax
+
+ ; Restore all general purpose host registers.
+ mov eax, VERR_VMX_INVALID_VMCS_PTR_TO_START_VM
+ jmp .vmstart64_end
+
+.vmstart64_start_failed:
+ pop rsi ; pCtx (needed in rsi by the macros below)
+
+%ifdef VMX_USE_CACHED_VMCS_ACCESSES
+ pop rdi ; pCache
+
+ %ifdef DEBUG
+ mov [rdi + VMCSCACHE.TestOut.pCache], rdi
+ mov [rdi + VMCSCACHE.TestOut.pCtx], rsi
+ %endif
+ %ifdef VBOX_WITH_CRASHDUMP_MAGIC
+ mov dword [rdi + VMCSCACHE.uPos], 11
+ %endif
+%endif
+
+ ; Restore segment registers.
+ MYPOPSEGS rax
+
+ ; Restore all general purpose host registers.
+ mov eax, VERR_VMX_UNABLE_TO_START_VM
+ jmp .vmstart64_end
+ENDPROC VMXRCStartVM64
+
+
+;/**
+; * Prepares for and executes VMRUN (64 bits guests)
+; *
+; * @returns VBox status code
+; * @param HCPhysVMCB Physical address of host VMCB (rsp+8)
+; * @param HCPhysVMCB Physical address of guest VMCB (rsp+16)
+; * @param pCtx Guest context (rsi)
+; */
+BEGINPROC SVMRCVMRun64
+ push rbp
+ mov rbp, rsp
+ pushf
+ DEBUG_CMOS_STACK64 30h
+
+ ; Manual save and restore:
+ ; - General purpose registers except RIP, RSP, RAX
+ ;
+ ; Trashed:
+ ; - CR2 (we don't care)
+ ; - LDTR (reset to 0)
+ ; - DRx (presumably not changed at all)
+ ; - DR7 (reset to 0x400)
+
+ ; Save the Guest CPU context pointer.
+ push rsi ; Push for saving the state at the end
+
+ ; Save host fs, gs, sysenter msr etc
+ mov rax, [rbp + 8 + 8] ; pVMCBHostPhys (64 bits physical address)
+ push rax ; Save for the vmload after vmrun
+ vmsave
+
+ ; Setup eax for VMLOAD
+ mov rax, [rbp + 8 + 8 + RTHCPHYS_CB] ; pVMCBPhys (64 bits physical address)
+
+ ; Restore Guest's general purpose registers.
+ ; rax is loaded from the VMCB by VMRUN.
+ mov rbx, qword [rsi + CPUMCTX.ebx]
+ mov rcx, qword [rsi + CPUMCTX.ecx]
+ mov rdx, qword [rsi + CPUMCTX.edx]
+ mov rdi, qword [rsi + CPUMCTX.edi]
+ mov rbp, qword [rsi + CPUMCTX.ebp]
+ mov r8, qword [rsi + CPUMCTX.r8]
+ mov r9, qword [rsi + CPUMCTX.r9]
+ mov r10, qword [rsi + CPUMCTX.r10]
+ mov r11, qword [rsi + CPUMCTX.r11]
+ mov r12, qword [rsi + CPUMCTX.r12]
+ mov r13, qword [rsi + CPUMCTX.r13]
+ mov r14, qword [rsi + CPUMCTX.r14]
+ mov r15, qword [rsi + CPUMCTX.r15]
+ mov rsi, qword [rsi + CPUMCTX.esi]
+
+ ; Clear the global interrupt flag & execute sti to make sure external interrupts cause a world switch.
+ clgi
+ sti
+
+ ; Load guest fs, gs, sysenter msr etc
+ vmload
+ ; Run the VM
+ vmrun
+
+ ; rax is in the VMCB already; we can use it here.
+
+ ; Save guest fs, gs, sysenter msr etc.
+ vmsave
+
+ ; Load host fs, gs, sysenter msr etc.
+ pop rax ; Pushed above
+ vmload
+
+ ; Set the global interrupt flag again, but execute cli to make sure IF=0.
+ cli
+ stgi
+
+ pop rax ; pCtx
+
+ mov qword [rax + CPUMCTX.ebx], rbx
+ mov qword [rax + CPUMCTX.ecx], rcx
+ mov qword [rax + CPUMCTX.edx], rdx
+ mov qword [rax + CPUMCTX.esi], rsi
+ mov qword [rax + CPUMCTX.edi], rdi
+ mov qword [rax + CPUMCTX.ebp], rbp
+ mov qword [rax + CPUMCTX.r8], r8
+ mov qword [rax + CPUMCTX.r9], r9
+ mov qword [rax + CPUMCTX.r10], r10
+ mov qword [rax + CPUMCTX.r11], r11
+ mov qword [rax + CPUMCTX.r12], r12
+ mov qword [rax + CPUMCTX.r13], r13
+ mov qword [rax + CPUMCTX.r14], r14
+ mov qword [rax + CPUMCTX.r15], r15
+
+ mov eax, VINF_SUCCESS
+
+ popf
+ pop rbp
+ ret
+ENDPROC SVMRCVMRun64
+
+;/**
+; * Saves the guest FPU context
+; *
+; * @returns VBox status code
+; * @param pCtx Guest context [rsi]
+; */
+BEGINPROC HMRCSaveGuestFPU64
+ DEBUG_CMOS_STACK64 40h
+ mov rax, cr0
+ mov rcx, rax ; save old CR0
+ and rax, ~(X86_CR0_TS | X86_CR0_EM)
+ mov cr0, rax
+
+ ; Use explicit REX prefix. See @bugref{6398}.
+ o64 fxsave [rsi + CPUMCTX.fpu]
+
+ mov cr0, rcx ; and restore old CR0 again
+
+ mov eax, VINF_SUCCESS
+ ret
+ENDPROC HMRCSaveGuestFPU64
+
+;/**
+; * Saves the guest debug context (DR0-3, DR6)
+; *
+; * @returns VBox status code
+; * @param pCtx Guest context [rsi]
+; */
+BEGINPROC HMRCSaveGuestDebug64
+ DEBUG_CMOS_STACK64 41h
+ mov rax, dr0
+ mov qword [rsi + CPUMCTX.dr + 0*8], rax
+ mov rax, dr1
+ mov qword [rsi + CPUMCTX.dr + 1*8], rax
+ mov rax, dr2
+ mov qword [rsi + CPUMCTX.dr + 2*8], rax
+ mov rax, dr3
+ mov qword [rsi + CPUMCTX.dr + 3*8], rax
+ mov rax, dr6
+ mov qword [rsi + CPUMCTX.dr + 6*8], rax
+ mov eax, VINF_SUCCESS
+ ret
+ENDPROC HMRCSaveGuestDebug64
+
+;/**
+; * Dummy callback handler
+; *
+; * @returns VBox status code
+; * @param param1 Parameter 1 [rsp+8]
+; * @param param2 Parameter 2 [rsp+12]
+; * @param param3 Parameter 3 [rsp+16]
+; * @param param4 Parameter 4 [rsp+20]
+; * @param param5 Parameter 5 [rsp+24]
+; * @param pCtx Guest context [rsi]
+; */
+BEGINPROC HMRCTestSwitcher64
+ DEBUG_CMOS_STACK64 42h
+ mov eax, [rsp+8]
+ ret
+ENDPROC HMRCTestSwitcher64
+
+
+%ifdef VBOX_WITH_64ON32_IDT
+;
+; Trap handling.
+;
+
+;; Here follows an array of trap handler entry points, 8 byte in size.
+BEGINPROC vmm64On32TrapHandlers
+%macro vmm64On32TrapEntry 1
+GLOBALNAME vmm64On32Trap %+ i
+ db 06ah, i ; push imm8 - note that this is a signextended value.
+ jmp NAME(%1)
+ ALIGNCODE(8)
+%assign i i+1
+%endmacro
+%assign i 0 ; start counter.
+ vmm64On32TrapEntry vmm64On32Trap ; 0
+ vmm64On32TrapEntry vmm64On32Trap ; 1
+ vmm64On32TrapEntry vmm64On32Trap ; 2
+ vmm64On32TrapEntry vmm64On32Trap ; 3
+ vmm64On32TrapEntry vmm64On32Trap ; 4
+ vmm64On32TrapEntry vmm64On32Trap ; 5
+ vmm64On32TrapEntry vmm64On32Trap ; 6
+ vmm64On32TrapEntry vmm64On32Trap ; 7
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; 8
+ vmm64On32TrapEntry vmm64On32Trap ; 9
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; a
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; b
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; c
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; d
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; e
+ vmm64On32TrapEntry vmm64On32Trap ; f (reserved)
+ vmm64On32TrapEntry vmm64On32Trap ; 10
+ vmm64On32TrapEntry vmm64On32TrapErrCode ; 11
+ vmm64On32TrapEntry vmm64On32Trap ; 12
+ vmm64On32TrapEntry vmm64On32Trap ; 13
+%rep (0x100 - 0x14)
+ vmm64On32TrapEntry vmm64On32Trap
+%endrep
+ENDPROC vmm64On32TrapHandlers
+
+;; Fake an error code and jump to the real thing.
+BEGINPROC vmm64On32Trap
+ push qword [rsp]
+ jmp NAME(vmm64On32TrapErrCode)
+ENDPROC vmm64On32Trap
+
+
+;;
+; Trap frame:
+; [rbp + 38h] = ss
+; [rbp + 30h] = rsp
+; [rbp + 28h] = eflags
+; [rbp + 20h] = cs
+; [rbp + 18h] = rip
+; [rbp + 10h] = error code (or trap number)
+; [rbp + 08h] = trap number
+; [rbp + 00h] = rbp
+; [rbp - 08h] = rax
+; [rbp - 10h] = rbx
+; [rbp - 18h] = ds
+;
+BEGINPROC vmm64On32TrapErrCode
+ push rbp
+ mov rbp, rsp
+ push rax
+ push rbx
+ mov ax, ds
+ push rax
+ sub rsp, 20h
+
+ mov ax, cs
+ mov ds, ax
+
+%if 1
+ COM64_S_NEWLINE
+ COM64_S_CHAR '!'
+ COM64_S_CHAR 't'
+ COM64_S_CHAR 'r'
+ COM64_S_CHAR 'a'
+ COM64_S_CHAR 'p'
+ movzx eax, byte [rbp + 08h]
+ COM64_S_DWORD_REG eax
+ COM64_S_CHAR '!'
+%endif
+
+%if 0 ;; @todo Figure the offset of the CPUMCPU relative to CPUM
+ sidt [rsp]
+ movsx eax, word [rsp]
+ shr eax, 12 ; div by 16 * 256 (0x1000).
+%else
+ ; hardcoded VCPU(0) for now...
+ mov rbx, [NAME(pCpumIC) wrt rip]
+ mov eax, [rbx + CPUM.offCPUMCPU0]
+%endif
+ push rax ; Save the offset for rbp later.
+
+ add rbx, rax ; rbx = CPUMCPU
+
+ ;
+ ; Deal with recursive traps due to vmxoff (lazy bird).
+ ;
+ lea rax, [.vmxoff_trap_location wrt rip]
+ cmp rax, [rbp + 18h]
+ je .not_vmx_root
+
+ ;
+ ; Save the context.
+ ;
+ mov rax, [rbp - 8]
+ mov [rbx + CPUMCPU.Hyper.eax], rax
+ mov [rbx + CPUMCPU.Hyper.ecx], rcx
+ mov [rbx + CPUMCPU.Hyper.edx], rdx
+ mov rax, [rbp - 10h]
+ mov [rbx + CPUMCPU.Hyper.ebx], rax
+ mov rax, [rbp]
+ mov [rbx + CPUMCPU.Hyper.ebp], rax
+ mov rax, [rbp + 30h]
+ mov [rbx + CPUMCPU.Hyper.esp], rax
+ mov [rbx + CPUMCPU.Hyper.edi], rdi
+ mov [rbx + CPUMCPU.Hyper.esi], rsi
+ mov [rbx + CPUMCPU.Hyper.r8], r8
+ mov [rbx + CPUMCPU.Hyper.r9], r9
+ mov [rbx + CPUMCPU.Hyper.r10], r10
+ mov [rbx + CPUMCPU.Hyper.r11], r11
+ mov [rbx + CPUMCPU.Hyper.r12], r12
+ mov [rbx + CPUMCPU.Hyper.r13], r13
+ mov [rbx + CPUMCPU.Hyper.r14], r14
+ mov [rbx + CPUMCPU.Hyper.r15], r15
+
+ mov rax, [rbp + 18h]
+ mov [rbx + CPUMCPU.Hyper.eip], rax
+ movzx ax, [rbp + 20h]
+ mov [rbx + CPUMCPU.Hyper.cs.Sel], ax
+ mov ax, [rbp + 38h]
+ mov [rbx + CPUMCPU.Hyper.ss.Sel], ax
+ mov ax, [rbp - 18h]
+ mov [rbx + CPUMCPU.Hyper.ds.Sel], ax
+
+ mov rax, [rbp + 28h]
+ mov [rbx + CPUMCPU.Hyper.eflags], rax
+
+ mov rax, cr2
+ mov [rbx + CPUMCPU.Hyper.cr2], rax
+
+ mov rax, [rbp + 10h]
+ mov [rbx + CPUMCPU.Hyper.r14], rax ; r14 = error code
+ movzx eax, byte [rbp + 08h]
+ mov [rbx + CPUMCPU.Hyper.r15], rax ; r15 = trap number
+
+ ;
+ ; Finally, leave VMX root operation before trying to return to the host.
+ ;
+ mov rax, cr4
+ test rax, X86_CR4_VMXE
+ jz .not_vmx_root
+.vmxoff_trap_location:
+ vmxoff
+.not_vmx_root:
+
+ ;
+ ; Go back to the host.
+ ;
+ pop rbp
+ mov dword [rbx + CPUMCPU.u32RetCode], VERR_TRPM_DONT_PANIC
+ jmp NAME(vmmRCToHostAsm)
+ENDPROC vmm64On32TrapErrCode
+
+;; We allocate the IDT here to avoid having to allocate memory separately somewhere.
+ALIGNCODE(16)
+GLOBALNAME vmm64On32Idt
+%assign i 0
+%rep 256
+ dq NAME(vmm64On32Trap %+ i) - NAME(Start) ; Relative trap handler offsets.
+ dq 0
+%assign i (i + 1)
+%endrep
+
+
+ %if 0
+;; For debugging purposes.
+BEGINPROC vmm64On32PrintIdtr
+ push rax
+ push rsi ; paranoia
+ push rdi ; ditto
+ sub rsp, 16
+
+ COM64_S_CHAR ';'
+ COM64_S_CHAR 'i'
+ COM64_S_CHAR 'd'
+ COM64_S_CHAR 't'
+ COM64_S_CHAR 'r'
+ COM64_S_CHAR '='
+ sidt [rsp + 6]
+ mov eax, [rsp + 8 + 4]
+ COM64_S_DWORD_REG eax
+ mov eax, [rsp + 8]
+ COM64_S_DWORD_REG eax
+ COM64_S_CHAR ':'
+ movzx eax, word [rsp + 6]
+ COM64_S_DWORD_REG eax
+ COM64_S_CHAR '!'
+
+ add rsp, 16
+ pop rdi
+ pop rsi
+ pop rax
+ ret
+ENDPROC vmm64On32PrintIdtr
+ %endif
+
+ %if 1
+;; For debugging purposes.
+BEGINPROC vmm64On32DumpCmos
+ push rax
+ push rdx
+ push rcx
+ push rsi ; paranoia
+ push rdi ; ditto
+ sub rsp, 16
+
+%if 0
+ mov al, 3
+ out 72h, al
+ mov al, 68h
+ out 73h, al
+%endif
+
+ COM64_S_NEWLINE
+ COM64_S_CHAR 'c'
+ COM64_S_CHAR 'm'
+ COM64_S_CHAR 'o'
+ COM64_S_CHAR 's'
+ COM64_S_CHAR '0'
+ COM64_S_CHAR ':'
+
+ xor ecx, ecx
+.loop1:
+ mov al, cl
+ out 70h, al
+ in al, 71h
+ COM64_S_BYTE_REG eax
+ COM64_S_CHAR ' '
+ inc ecx
+ cmp ecx, 128
+ jb .loop1
+
+ COM64_S_NEWLINE
+ COM64_S_CHAR 'c'
+ COM64_S_CHAR 'm'
+ COM64_S_CHAR 'o'
+ COM64_S_CHAR 's'
+ COM64_S_CHAR '1'
+ COM64_S_CHAR ':'
+ xor ecx, ecx
+.loop2:
+ mov al, cl
+ out 72h, al
+ in al, 73h
+ COM64_S_BYTE_REG eax
+ COM64_S_CHAR ' '
+ inc ecx
+ cmp ecx, 128
+ jb .loop2
+
+%if 0
+ COM64_S_NEWLINE
+ COM64_S_CHAR 'c'
+ COM64_S_CHAR 'm'
+ COM64_S_CHAR 'o'
+ COM64_S_CHAR 's'
+ COM64_S_CHAR '2'
+ COM64_S_CHAR ':'
+ xor ecx, ecx
+.loop3:
+ mov al, cl
+ out 74h, al
+ in al, 75h
+ COM64_S_BYTE_REG eax
+ COM64_S_CHAR ' '
+ inc ecx
+ cmp ecx, 128
+ jb .loop3
+
+ COM64_S_NEWLINE
+ COM64_S_CHAR 'c'
+ COM64_S_CHAR 'm'
+ COM64_S_CHAR 'o'
+ COM64_S_CHAR 's'
+ COM64_S_CHAR '3'
+ COM64_S_CHAR ':'
+ xor ecx, ecx
+.loop4:
+ mov al, cl
+ out 72h, al
+ in al, 73h
+ COM64_S_BYTE_REG eax
+ COM64_S_CHAR ' '
+ inc ecx
+ cmp ecx, 128
+ jb .loop4
+
+ COM64_S_NEWLINE
+%endif
+
+ add rsp, 16
+ pop rdi
+ pop rsi
+ pop rcx
+ pop rdx
+ pop rax
+ ret
+ENDPROC vmm64On32DumpCmos
+ %endif
+
+%endif ; VBOX_WITH_64ON32_IDT
+
+
+
+;
+;
+; Back to switcher code.
+; Back to switcher code.
+; Back to switcher code.
+;
+;
+
+
+
;;
; Trampoline for doing a call when starting the hyper visor execution.
;
@@ -491,11 +1663,11 @@ BEGINPROC vmmRCToHost
%ifdef DEBUG_STUFF
push rsi
COM_NEWLINE
- DEBUG_CHAR('b')
- DEBUG_CHAR('a')
- DEBUG_CHAR('c')
- DEBUG_CHAR('k')
- DEBUG_CHAR('!')
+ COM_CHAR 'b'
+ COM_CHAR 'a'
+ COM_CHAR 'c'
+ COM_CHAR 'k'
+ COM_CHAR '!'
COM_NEWLINE
pop rsi
%endif
@@ -509,8 +1681,8 @@ ENDPROC vmmRCToHost
; when the we have saved the guest state already or we haven't
; been messing with the guest at all.
;
-; @param eax Return code.
-; @uses eax, edx, ecx (or it may use them in the future)
+; @param rbp The virtual cpu number.
+; @param
;
BITS 64
ALIGNCODE(16)
@@ -534,34 +1706,34 @@ dd 0
ALIGNCODE(16)
GLOBALNAME IDExitTarget
BITS 32
- DEBUG_CHAR('1')
+ DEBUG32_CHAR('1')
; 1. Deactivate long mode by turning off paging.
mov ebx, cr0
and ebx, ~X86_CR0_PG
mov cr0, ebx
- DEBUG_CHAR('2')
+ DEBUG32_CHAR('2')
; 2. Load intermediate page table.
FIXUP SWITCHER_FIX_INTER_CR3_HC, 1
mov edx, 0ffffffffh
mov cr3, edx
- DEBUG_CHAR('3')
+ DEBUG32_CHAR('3')
; 3. Disable long mode.
mov ecx, MSR_K6_EFER
rdmsr
- DEBUG_CHAR('5')
+ DEBUG32_CHAR('5')
and eax, ~(MSR_K6_EFER_LME)
wrmsr
- DEBUG_CHAR('6')
+ DEBUG32_CHAR('6')
%ifndef NEED_PAE_ON_HOST
; 3b. Disable PAE.
mov eax, cr4
and eax, ~X86_CR4_PAE
mov cr4, eax
- DEBUG_CHAR('7')
+ DEBUG32_CHAR('7')
%endif
; 4. Enable paging.
@@ -569,7 +1741,7 @@ BITS 32
mov cr0, ebx
jmp short just_a_jump
just_a_jump:
- DEBUG_CHAR('8')
+ DEBUG32_CHAR('8')
;;
;; 5. Jump to guest code mapping of the code and load the Hypervisor CS.
@@ -578,44 +1750,52 @@ just_a_jump:
jmp near NAME(ICExitTarget)
;;
- ;; When we arrive at this label we're at the
- ;; intermediate mapping of the switching code.
+ ;; When we arrive at this label we're at the host mapping of the
+ ;; switcher code, but with intermediate page tables.
;;
BITS 32
ALIGNCODE(16)
GLOBALNAME ICExitTarget
- DEBUG_CHAR('8')
+ DEBUG32_CHAR('9')
+ ;DEBUG_CMOS_TRASH_AL 70h
; load the hypervisor data selector into ds & es
FIXUP FIX_HYPER_DS, 1
mov eax, 0ffffh
mov ds, eax
mov es, eax
+ DEBUG32_CHAR('a')
FIXUP FIX_GC_CPUM_OFF, 1, 0
mov edx, 0ffffffffh
CPUMCPU_FROM_CPUM_WITH_OFFSET edx, ebp
+
+ DEBUG32_CHAR('b')
mov esi, [edx + CPUMCPU.Host.cr3]
mov cr3, esi
+ DEBUG32_CHAR('c')
;; now we're in host memory context, let's restore regs
FIXUP FIX_HC_CPUM_OFF, 1, 0
mov edx, 0ffffffffh
CPUMCPU_FROM_CPUM_WITH_OFFSET edx, ebp
+ DEBUG32_CHAR('e')
; restore the host EFER
mov ebx, edx
mov ecx, MSR_K6_EFER
mov eax, [ebx + CPUMCPU.Host.efer]
mov edx, [ebx + CPUMCPU.Host.efer + 4]
+ DEBUG32_CHAR('f')
wrmsr
mov edx, ebx
+ DEBUG32_CHAR('g')
; activate host gdt and idt
lgdt [edx + CPUMCPU.Host.gdtr]
- DEBUG_CHAR('0')
+ DEBUG32_CHAR('0')
lidt [edx + CPUMCPU.Host.idtr]
- DEBUG_CHAR('1')
+ DEBUG32_CHAR('1')
; Restore TSS selector; must mark it as not busy before using ltr (!)
; ASSUME that this is supposed to be 'BUSY'. (saves 20-30 ticks on the T42p)
@@ -626,7 +1806,7 @@ GLOBALNAME ICExitTarget
ltr word [edx + CPUMCPU.Host.tr]
; activate ldt
- DEBUG_CHAR('2')
+ DEBUG32_CHAR('2')
lldt [edx + CPUMCPU.Host.ldtr]
; Restore segment registers
@@ -656,6 +1836,7 @@ GLOBALNAME ICExitTarget
mov ebp, [edx + CPUMCPU.Host.ebp]
; store the return code in eax
+ DEBUG_CMOS_TRASH_AL 79h
mov eax, [edx + CPUMCPU.u32RetCode]
retf
ENDPROC vmmRCToHostAsm
@@ -703,7 +1884,11 @@ GLOBALNAME Def
at VMMSWITCHERDEF.cbIDCode0, dd NAME(ICEnterTarget) - NAME(IDEnterTarget)
at VMMSWITCHERDEF.offIDCode1, dd NAME(IDExitTarget) - NAME(Start)
at VMMSWITCHERDEF.cbIDCode1, dd NAME(ICExitTarget) - NAME(Start)
+%ifdef VBOX_WITH_64ON32_IDT ; Hack! Use offGCCode to find the IDT.
+ at VMMSWITCHERDEF.offGCCode, dd NAME(vmm64On32Idt) - NAME(Start)
+%else
at VMMSWITCHERDEF.offGCCode, dd 0
+%endif
at VMMSWITCHERDEF.cbGCCode, dd 0
iend