VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HMR0A.asm@ 87443

Last change on this file since 87443 was 87443, checked in by vboxsync, 4 years ago

VMM/HMVMX,HMSVM: Baked the hmR0VMXStartVMWrapXMM fun into the hmR0VmxStartVm template like already done for SVM. Fixed copy&paste bug in non-volatile xmm register restoring in hmR0SvmVmRun.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 62.2 KB
Line 
1; $Id: HMR0A.asm 87443 2021-01-26 20:32:56Z vboxsync $
2;; @file
3; HM - Ring-0 VMX, SVM world-switch and helper routines.
4;
5
6;
7; Copyright (C) 2006-2020 Oracle Corporation
8;
9; This file is part of VirtualBox Open Source Edition (OSE), as
10; available from http://www.virtualbox.org. This file is free software;
11; you can redistribute it and/or modify it under the terms of the GNU
12; General Public License (GPL) as published by the Free Software
13; Foundation, in version 2 as it comes in the "COPYING" file of the
14; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16;
17
18;*********************************************************************************************************************************
19;* Header Files *
20;*********************************************************************************************************************************
21;%define RT_ASM_WITH_SEH64 - trouble with SEH, alignment and (probably) 2nd pass optimizations.
22%include "VBox/asmdefs.mac"
23%include "VBox/err.mac"
24%include "VBox/vmm/hm_vmx.mac"
25%include "VBox/vmm/cpum.mac"
26%include "VBox/vmm/vm.mac"
27%include "iprt/x86.mac"
28%include "HMInternal.mac"
29
30%ifndef RT_ARCH_AMD64
31 %error AMD64 only.
32%endif
33
34
35;*********************************************************************************************************************************
36;* Defined Constants And Macros *
37;*********************************************************************************************************************************
38;; The offset of the XMM registers in X86FXSTATE.
39; Use define because I'm too lazy to convert the struct.
40%define XMM_OFF_IN_X86FXSTATE 160
41
42;; Spectre filler for 64-bit mode.
43; Choosen to be an invalid address (also with 5 level paging).
44%define SPECTRE_FILLER 0x02204204207fffff
45
46;;
47; Determine skipping restoring of GDTR, IDTR, TR across VMX non-root operation.
48;
49; @note This is normally done by hmR0VmxExportHostSegmentRegs and VMXRestoreHostState,
50; so much of this is untested code.
51; @{
52%define VMX_SKIP_GDTR
53%define VMX_SKIP_TR
54%define VBOX_SKIP_RESTORE_SEG
55%ifdef RT_OS_DARWIN
56 ; Load the NULL selector into DS, ES, FS and GS on 64-bit darwin so we don't
57 ; risk loading a stale LDT value or something invalid.
58 %define HM_64_BIT_USE_NULL_SEL
59 ; Darwin (Mavericks) uses IDTR limit to store the CPU number so we need to always restore it.
60 ; See @bugref{6875}.
61 %undef VMX_SKIP_IDTR
62%else
63 %define VMX_SKIP_IDTR
64%endif
65;; @}
66
67;; @def CALLEE_PRESERVED_REGISTER_COUNT
68; Number of registers pushed by PUSH_CALLEE_PRESERVED_REGISTERS
69%ifdef ASM_CALL64_GCC
70 %define CALLEE_PRESERVED_REGISTER_COUNT 5
71%else
72 %define CALLEE_PRESERVED_REGISTER_COUNT 7
73%endif
74
75;; @def PUSH_CALLEE_PRESERVED_REGISTERS
76; Macro for pushing all GPRs we must preserve for the caller.
77%macro PUSH_CALLEE_PRESERVED_REGISTERS 0
78 push r15
79 SEH64_PUSH_GREG r15
80 %assign cbFrame cbFrame + 8
81 %assign frm_saved_r15 -cbFrame
82
83 push r14
84 SEH64_PUSH_GREG r14
85 %assign cbFrame cbFrame + 8
86 %assign frm_saved_r14 -cbFrame
87
88 push r13
89 SEH64_PUSH_GREG r13
90 %assign cbFrame cbFrame + 8
91 %assign frm_saved_r13 -cbFrame
92
93 push r12
94 SEH64_PUSH_GREG r12
95 %assign cbFrame cbFrame + 8
96 %assign frm_saved_r12 -cbFrame
97
98 push rbx
99 SEH64_PUSH_GREG rbx
100 %assign cbFrame cbFrame + 8
101 %assign frm_saved_rbx -cbFrame
102
103 %ifdef ASM_CALL64_MSC
104 push rsi
105 SEH64_PUSH_GREG rsi
106 %assign cbFrame cbFrame + 8
107 %assign frm_saved_rsi -cbFrame
108
109 push rdi
110 SEH64_PUSH_GREG rdi
111 %assign cbFrame cbFrame + 8
112 %assign frm_saved_rdi -cbFrame
113 %endif
114%endmacro
115
116;; @def POP_CALLEE_PRESERVED_REGISTERS
117; Counterpart to PUSH_CALLEE_PRESERVED_REGISTERS for use in the epilogue.
118%macro POP_CALLEE_PRESERVED_REGISTERS 0
119 %ifdef ASM_CALL64_MSC
120 pop rdi
121 %assign cbFrame cbFrame - 8
122 %undef frm_saved_rdi
123
124 pop rsi
125 %assign cbFrame cbFrame - 8
126 %undef frm_saved_rsi
127 %endif
128 pop rbx
129 %assign cbFrame cbFrame - 8
130 %undef frm_saved_rbx
131
132 pop r12
133 %assign cbFrame cbFrame - 8
134 %undef frm_saved_r12
135
136 pop r13
137 %assign cbFrame cbFrame - 8
138 %undef frm_saved_r13
139
140 pop r14
141 %assign cbFrame cbFrame - 8
142 %undef frm_saved_r14
143
144 pop r15
145 %assign cbFrame cbFrame - 8
146 %undef frm_saved_r15
147%endmacro
148
149
150;; @def PUSH_RELEVANT_SEGMENT_REGISTERS
151; Macro saving all segment registers on the stack.
152; @param 1 Full width register name.
153; @param 2 16-bit register name for \a 1.
154; @cobbers rax, rdx, rcx
155%macro PUSH_RELEVANT_SEGMENT_REGISTERS 2
156 %ifndef VBOX_SKIP_RESTORE_SEG
157 %error untested code. probably does not work any more!
158 %ifndef HM_64_BIT_USE_NULL_SEL
159 mov %2, es
160 push %1
161 mov %2, ds
162 push %1
163 %endif
164
165 ; Special case for FS; Windows and Linux either don't use it or restore it when leaving kernel mode,
166 ; Solaris OTOH doesn't and we must save it.
167 mov ecx, MSR_K8_FS_BASE
168 rdmsr
169 push rdx
170 push rax
171 %ifndef HM_64_BIT_USE_NULL_SEL
172 push fs
173 %endif
174
175 ; Special case for GS; OSes typically use swapgs to reset the hidden base register for GS on entry into the kernel.
176 ; The same happens on exit.
177 mov ecx, MSR_K8_GS_BASE
178 rdmsr
179 push rdx
180 push rax
181 %ifndef HM_64_BIT_USE_NULL_SEL
182 push gs
183 %endif
184 %endif ; !VBOX_SKIP_RESTORE_SEG
185%endmacro ; PUSH_RELEVANT_SEGMENT_REGISTERS
186
187;; @def POP_RELEVANT_SEGMENT_REGISTERS
188; Macro restoring all segment registers on the stack.
189; @param 1 Full width register name.
190; @param 2 16-bit register name for \a 1.
191; @cobbers rax, rdx, rcx
192%macro POP_RELEVANT_SEGMENT_REGISTERS 2
193 %ifndef VBOX_SKIP_RESTORE_SEG
194 %error untested code. probably does not work any more!
195 ; Note: do not step through this code with a debugger!
196 %ifndef HM_64_BIT_USE_NULL_SEL
197 xor eax, eax
198 mov ds, ax
199 mov es, ax
200 mov fs, ax
201 mov gs, ax
202 %endif
203
204 %ifndef HM_64_BIT_USE_NULL_SEL
205 pop gs
206 %endif
207 pop rax
208 pop rdx
209 mov ecx, MSR_K8_GS_BASE
210 wrmsr
211
212 %ifndef HM_64_BIT_USE_NULL_SEL
213 pop fs
214 %endif
215 pop rax
216 pop rdx
217 mov ecx, MSR_K8_FS_BASE
218 wrmsr
219 ; Now it's safe to step again
220
221 %ifndef HM_64_BIT_USE_NULL_SEL
222 pop %1
223 mov ds, %2
224 pop %1
225 mov es, %2
226 %endif
227 %endif ; !VBOX_SKIP_RESTORE_SEG
228%endmacro ; POP_RELEVANT_SEGMENT_REGISTERS
229
230
231;;
232; Creates an indirect branch prediction barrier on CPUs that need and supports that.
233; @clobbers eax, edx, ecx
234; @param 1 How to address CPUMCTX.
235; @param 2 Which flag to test for (CPUMCTX_WSF_IBPB_ENTRY or CPUMCTX_WSF_IBPB_EXIT)
236%macro INDIRECT_BRANCH_PREDICTION_BARRIER_CTX 2
237 test byte [%1 + CPUMCTX.fWorldSwitcher], %2
238 jz %%no_indirect_branch_barrier
239 mov ecx, MSR_IA32_PRED_CMD
240 mov eax, MSR_IA32_PRED_CMD_F_IBPB
241 xor edx, edx
242 wrmsr
243%%no_indirect_branch_barrier:
244%endmacro
245
246;;
247; Creates an indirect branch prediction barrier on CPUs that need and supports that.
248; @clobbers eax, edx, ecx
249; @param 1 How to address VMCPU.
250; @param 2 Which flag to test for (CPUMCTX_WSF_IBPB_ENTRY or CPUMCTX_WSF_IBPB_EXIT)
251%macro INDIRECT_BRANCH_PREDICTION_BARRIER 2
252 test byte [%1 + VMCPU.cpum.GstCtx + CPUMCTX.fWorldSwitcher], %2
253 jz %%no_indirect_branch_barrier
254 mov ecx, MSR_IA32_PRED_CMD
255 mov eax, MSR_IA32_PRED_CMD_F_IBPB
256 xor edx, edx
257 wrmsr
258%%no_indirect_branch_barrier:
259%endmacro
260
261;;
262; Creates an indirect branch prediction and L1D barrier on CPUs that need and supports that.
263; @clobbers eax, edx, ecx
264; @param 1 How to address CPUMCTX.
265; @param 2 Which IBPB flag to test for (CPUMCTX_WSF_IBPB_ENTRY or CPUMCTX_WSF_IBPB_EXIT)
266; @param 3 Which FLUSH flag to test for (CPUMCTX_WSF_L1D_ENTRY)
267; @param 4 Which MDS flag to test for (CPUMCTX_WSF_MDS_ENTRY)
268%macro INDIRECT_BRANCH_PREDICTION_AND_L1_CACHE_BARRIER 4
269 ; Only one test+jmp when disabled CPUs.
270 test byte [%1 + CPUMCTX.fWorldSwitcher], (%2 | %3 | %4)
271 jz %%no_barrier_needed
272
273 ; The eax:edx value is the same for both.
274 AssertCompile(MSR_IA32_PRED_CMD_F_IBPB == MSR_IA32_FLUSH_CMD_F_L1D)
275 mov eax, MSR_IA32_PRED_CMD_F_IBPB
276 xor edx, edx
277
278 ; Indirect branch barrier.
279 test byte [%1 + CPUMCTX.fWorldSwitcher], %2
280 jz %%no_indirect_branch_barrier
281 mov ecx, MSR_IA32_PRED_CMD
282 wrmsr
283%%no_indirect_branch_barrier:
284
285 ; Level 1 data cache flush.
286 test byte [%1 + CPUMCTX.fWorldSwitcher], %3
287 jz %%no_cache_flush_barrier
288 mov ecx, MSR_IA32_FLUSH_CMD
289 wrmsr
290 jmp %%no_mds_buffer_flushing ; MDS flushing is included in L1D_FLUSH
291%%no_cache_flush_barrier:
292
293 ; MDS buffer flushing.
294 test byte [%1 + CPUMCTX.fWorldSwitcher], %4
295 jz %%no_mds_buffer_flushing
296 sub xSP, xSP
297 mov [xSP], ds
298 verw [xSP]
299 add xSP, xSP
300%%no_mds_buffer_flushing:
301
302%%no_barrier_needed:
303%endmacro
304
305
306;*********************************************************************************************************************************
307;* External Symbols *
308;*********************************************************************************************************************************
309%ifdef VBOX_WITH_KERNEL_USING_XMM
310extern NAME(CPUMIsGuestFPUStateActive)
311%endif
312
313
314BEGINCODE
315
316
317;;
318; Used on platforms with poor inline assembly support to retrieve all the
319; info from the CPU and put it in the @a pRestoreHost structure.
320;
321; @returns VBox status code
322; @param pRestoreHost msc: rcx gcc: rdi Pointer to the RestoreHost struct.
323; @param fHaveFsGsBase msc: dl gcc: sil Whether we can use rdfsbase or not.
324;
325ALIGNCODE(64)
326BEGINPROC hmR0VmxExportHostSegmentRegsAsmHlp
327%ifdef ASM_CALL64_MSC
328 %define pRestoreHost rcx
329%elifdef ASM_CALL64_GCC
330 %define pRestoreHost rdi
331%else
332 %error Unknown calling convension.
333%endif
334 SEH64_END_PROLOGUE
335
336 ; Start with the FS and GS base so we can trash DL/SIL.
337%ifdef ASM_CALL64_MSC
338 or dl, dl
339%else
340 or sil, sil
341%endif
342 jz .use_rdmsr_for_fs_and_gs_base
343 rdfsbase rax
344 mov [pRestoreHost + VMXRESTOREHOST.uHostFSBase], rax
345 rdgsbase rax
346 mov [pRestoreHost + VMXRESTOREHOST.uHostGSBase], rax
347.done_fs_and_gs_base:
348
349 ; TR, GDTR and IDTR
350 str [pRestoreHost + VMXRESTOREHOST.uHostSelTR]
351 sgdt [pRestoreHost + VMXRESTOREHOST.HostGdtr]
352 sidt [pRestoreHost + VMXRESTOREHOST.HostIdtr]
353
354 ; Segment registers.
355 xor eax, eax
356 mov eax, cs
357 mov [pRestoreHost + VMXRESTOREHOST.uHostSelCS], ax
358
359 mov eax, ss
360 mov [pRestoreHost + VMXRESTOREHOST.uHostSelSS], ax
361
362 mov eax, gs
363 mov [pRestoreHost + VMXRESTOREHOST.uHostSelGS], ax
364
365 mov eax, fs
366 mov [pRestoreHost + VMXRESTOREHOST.uHostSelFS], ax
367
368 mov eax, es
369 mov [pRestoreHost + VMXRESTOREHOST.uHostSelES], ax
370
371 mov eax, ds
372 mov [pRestoreHost + VMXRESTOREHOST.uHostSelDS], ax
373
374 ret
375
376ALIGNCODE(16)
377.use_rdmsr_for_fs_and_gs_base:
378%ifdef ASM_CALL64_MSC
379 mov r8, pRestoreHost
380%endif
381
382 mov ecx, MSR_K8_FS_BASE
383 rdmsr
384 shl rdx, 32
385 or rdx, rax
386 mov [r8 + VMXRESTOREHOST.uHostFSBase], rax
387
388 mov ecx, MSR_K8_GS_BASE
389 rdmsr
390 shl rdx, 32
391 or rdx, rax
392 mov [r8 + VMXRESTOREHOST.uHostGSBase], rax
393
394%ifdef ASM_CALL64_MSC
395 mov pRestoreHost, r8
396%endif
397 jmp .done_fs_and_gs_base
398%undef pRestoreHost
399ENDPROC hmR0VmxExportHostSegmentRegsAsmHlp
400
401
402;;
403; Restores host-state fields.
404;
405; @returns VBox status code
406; @param f32RestoreHost msc: ecx gcc: edi RestoreHost flags.
407; @param pRestoreHost msc: rdx gcc: rsi Pointer to the RestoreHost struct.
408;
409ALIGNCODE(64)
410BEGINPROC VMXRestoreHostState
411%ifndef ASM_CALL64_GCC
412 ; Use GCC's input registers since we'll be needing both rcx and rdx further
413 ; down with the wrmsr instruction. Use the R10 and R11 register for saving
414 ; RDI and RSI since MSC preserve the two latter registers.
415 mov r10, rdi
416 mov r11, rsi
417 mov rdi, rcx
418 mov rsi, rdx
419%endif
420 SEH64_END_PROLOGUE
421
422.restore_gdtr:
423 test edi, VMX_RESTORE_HOST_GDTR
424 jz .restore_idtr
425 lgdt [rsi + VMXRESTOREHOST.HostGdtr]
426
427.restore_idtr:
428 test edi, VMX_RESTORE_HOST_IDTR
429 jz .restore_ds
430 lidt [rsi + VMXRESTOREHOST.HostIdtr]
431
432.restore_ds:
433 test edi, VMX_RESTORE_HOST_SEL_DS
434 jz .restore_es
435 mov ax, [rsi + VMXRESTOREHOST.uHostSelDS]
436 mov ds, eax
437
438.restore_es:
439 test edi, VMX_RESTORE_HOST_SEL_ES
440 jz .restore_tr
441 mov ax, [rsi + VMXRESTOREHOST.uHostSelES]
442 mov es, eax
443
444.restore_tr:
445 test edi, VMX_RESTORE_HOST_SEL_TR
446 jz .restore_fs
447 ; When restoring the TR, we must first clear the busy flag or we'll end up faulting.
448 mov dx, [rsi + VMXRESTOREHOST.uHostSelTR]
449 mov ax, dx
450 and eax, X86_SEL_MASK_OFF_RPL ; mask away TI and RPL bits leaving only the descriptor offset
451 test edi, VMX_RESTORE_HOST_GDT_READ_ONLY | VMX_RESTORE_HOST_GDT_NEED_WRITABLE
452 jnz .gdt_readonly_or_need_writable
453 add rax, qword [rsi + VMXRESTOREHOST.HostGdtr + 2] ; xAX <- descriptor offset + GDTR.pGdt.
454 and dword [rax + 4], ~RT_BIT(9) ; clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit)
455 ltr dx
456
457.restore_fs:
458 ;
459 ; When restoring the selector values for FS and GS, we'll temporarily trash
460 ; the base address (at least the high 32-bit bits, but quite possibly the
461 ; whole base address), the wrmsr will restore it correctly. (VT-x actually
462 ; restores the base correctly when leaving guest mode, but not the selector
463 ; value, so there is little problem with interrupts being enabled prior to
464 ; this restore job.)
465 ; We'll disable ints once for both FS and GS as that's probably faster.
466 ;
467 test edi, VMX_RESTORE_HOST_SEL_FS | VMX_RESTORE_HOST_SEL_GS
468 jz .restore_success
469 pushfq
470 cli ; (see above)
471
472 test edi, VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE
473 jz .restore_fs_using_wrmsr
474
475.restore_fs_using_wrfsbase:
476 test edi, VMX_RESTORE_HOST_SEL_FS
477 jz .restore_gs_using_wrgsbase
478 mov rax, qword [rsi + VMXRESTOREHOST.uHostFSBase]
479 mov cx, word [rsi + VMXRESTOREHOST.uHostSelFS]
480 mov fs, ecx
481 wrfsbase rax
482
483.restore_gs_using_wrgsbase:
484 test edi, VMX_RESTORE_HOST_SEL_GS
485 jz .restore_flags
486 mov rax, qword [rsi + VMXRESTOREHOST.uHostGSBase]
487 mov cx, word [rsi + VMXRESTOREHOST.uHostSelGS]
488 mov gs, ecx
489 wrgsbase rax
490
491.restore_flags:
492 popfq
493
494.restore_success:
495 mov eax, VINF_SUCCESS
496%ifndef ASM_CALL64_GCC
497 ; Restore RDI and RSI on MSC.
498 mov rdi, r10
499 mov rsi, r11
500%endif
501 ret
502
503ALIGNCODE(8)
504.gdt_readonly_or_need_writable:
505 test edi, VMX_RESTORE_HOST_GDT_NEED_WRITABLE
506 jnz .gdt_readonly_need_writable
507.gdt_readonly:
508 mov rcx, cr0
509 mov r9, rcx
510 add rax, qword [rsi + VMXRESTOREHOST.HostGdtr + 2] ; xAX <- descriptor offset + GDTR.pGdt.
511 and rcx, ~X86_CR0_WP
512 mov cr0, rcx
513 and dword [rax + 4], ~RT_BIT(9) ; clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit)
514 ltr dx
515 mov cr0, r9
516 jmp .restore_fs
517
518ALIGNCODE(8)
519.gdt_readonly_need_writable:
520 add rax, qword [rsi + VMXRESTOREHOST.HostGdtrRw + 2] ; xAX <- descriptor offset + GDTR.pGdtRw
521 and dword [rax + 4], ~RT_BIT(9) ; clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit)
522 lgdt [rsi + VMXRESTOREHOST.HostGdtrRw]
523 ltr dx
524 lgdt [rsi + VMXRESTOREHOST.HostGdtr] ; load the original GDT
525 jmp .restore_fs
526
527ALIGNCODE(8)
528.restore_fs_using_wrmsr:
529 test edi, VMX_RESTORE_HOST_SEL_FS
530 jz .restore_gs_using_wrmsr
531 mov eax, dword [rsi + VMXRESTOREHOST.uHostFSBase] ; uHostFSBase - Lo
532 mov edx, dword [rsi + VMXRESTOREHOST.uHostFSBase + 4h] ; uHostFSBase - Hi
533 mov cx, word [rsi + VMXRESTOREHOST.uHostSelFS]
534 mov fs, ecx
535 mov ecx, MSR_K8_FS_BASE
536 wrmsr
537
538.restore_gs_using_wrmsr:
539 test edi, VMX_RESTORE_HOST_SEL_GS
540 jz .restore_flags
541 mov eax, dword [rsi + VMXRESTOREHOST.uHostGSBase] ; uHostGSBase - Lo
542 mov edx, dword [rsi + VMXRESTOREHOST.uHostGSBase + 4h] ; uHostGSBase - Hi
543 mov cx, word [rsi + VMXRESTOREHOST.uHostSelGS]
544 mov gs, ecx
545 mov ecx, MSR_K8_GS_BASE
546 wrmsr
547 jmp .restore_flags
548ENDPROC VMXRestoreHostState
549
550
551;;
552; Dispatches an NMI to the host.
553;
554ALIGNCODE(16)
555BEGINPROC VMXDispatchHostNmi
556 ; NMI is always vector 2. The IDT[2] IRQ handler cannot be anything else. See Intel spec. 6.3.1 "External Interrupts".
557 SEH64_END_PROLOGUE
558 int 2
559 ret
560ENDPROC VMXDispatchHostNmi
561
562
563;;
564; hmR0VmxStartVm template
565;
566; @param 1 The suffix of the variation.
567; @param 2 fLoadSaveGuestXcr0 value
568; @param 3 The CPUMCTX_WSF_IBPB_ENTRY + CPUMCTX_WSF_IBPB_EXIT value.
569; @param 4 The SSE saving/restoring: 0 to do nothing, 1 to do it manually, 2 to use xsave/xrstor.
570; Drivers shouldn't use AVX registers without saving+loading:
571; https://msdn.microsoft.com/en-us/library/windows/hardware/ff545910%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
572; However the compiler docs have different idea:
573; https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
574; We'll go with the former for now.
575;
576%macro hmR0VmxStartVmTemplate 4
577
578;;
579; Prepares for and executes VMLAUNCH/VMRESUME (64 bits guest mode)
580;
581; @returns VBox status code
582; @param pVM msc:rcx, gcc:rdi The cross context VM structure. (unused)
583; @param pVCpu msc:rdx, gcc:rsi The cross context virtual CPU structure of the calling EMT.
584; @param fResume msc:r8l, gcc:dl Whether to use vmlauch/vmresume.
585;
586ALIGNCODE(64)
587BEGINPROC RT_CONCAT(hmR0VmxStartVm,%1)
588 %ifdef VBOX_WITH_KERNEL_USING_XMM
589 %if %4 = 0
590 ;
591 ; The non-saving variant will currently check the two SSE preconditions and pick
592 ; the right variant to continue with. Later we can see if we can't manage to
593 ; move these decisions into hmR0VmxUpdateStartVmFunction().
594 ;
595 %ifdef ASM_CALL64_MSC
596 test byte [rdx + VMCPU.cpum.GstCtx + CPUMCTX.fUsedFpuGuest], 1
597 %else
598 test byte [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fUsedFpuGuest], 1
599 %endif
600 jz .save_xmm_no_need
601 %ifdef ASM_CALL64_MSC
602 cmp dword [rdx + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask], 0
603 %else
604 cmp dword [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask], 0
605 %endif
606 je RT_CONCAT3(hmR0VmxStartVm,%1,_SseManual)
607 jmp RT_CONCAT3(hmR0VmxStartVm,%1,_SseXSave)
608.save_xmm_no_need:
609 %endif
610 %endif
611 push xBP
612 SEH64_PUSH_xBP
613 mov xBP, xSP
614 SEH64_SET_FRAME_xBP 0
615 pushf
616 cli
617
618 %define frm_fRFlags -008h
619 %define frm_pGstCtx -010h ; Where we stash guest CPU context for use after the vmrun.
620 %define frm_uHostXcr0 -020h ; 128-bit
621 %define frm_saved_gdtr -02ah ; 16+64: Only used when VMX_SKIP_GDTR isn't defined
622 %define frm_saved_tr -02ch ; 16-bit: Only used when VMX_SKIP_TR isn't defined
623 %define frm_MDS_seg -030h ; 16-bit: Temporary storage for the MDS flushing.
624 %define frm_saved_idtr -03ah ; 16+64: Only used when VMX_SKIP_IDTR isn't defined
625 %define frm_saved_ldtr -03ch ; 16-bit: always saved.
626 %define frm_rcError -040h ; 32-bit: Error status code (not used in the success path)
627 %define frm_guest_rax -048h ; Temporary storage slot for guest RAX.
628 %if %4 = 0
629 %assign cbFrame 048h
630 %else
631 %define frm_saved_xmm6 -050h
632 %define frm_saved_xmm7 -060h
633 %define frm_saved_xmm8 -070h
634 %define frm_saved_xmm9 -080h
635 %define frm_saved_xmm10 -090h
636 %define frm_saved_xmm11 -0a0h
637 %define frm_saved_xmm12 -0b0h
638 %define frm_saved_xmm13 -0c0h
639 %define frm_saved_xmm14 -0d0h
640 %define frm_saved_xmm15 -0e0h
641 %define frm_saved_mxcsr -0f0h
642 %assign cbFrame 0f0h
643 %endif
644 %assign cbBaseFrame cbFrame
645 sub rsp, cbFrame - 8
646
647 ; Save all general purpose host registers.
648 PUSH_CALLEE_PRESERVED_REGISTERS
649 ;PUSH_RELEVANT_SEGMENT_REGISTERS xAX, ax - currently broken
650 SEH64_END_PROLOGUE
651
652 ;
653 ; Unify the input parameter registers: rsi=pVCpu, bl=fResume, rdi=&pVCpu->cpum.GstCtx;
654 ;
655 %ifdef ASM_CALL64_GCC
656 mov ebx, edx ; fResume
657 %else
658 mov rsi, rdx ; pVCpu
659 mov ebx, r8d ; fResume
660 %endif
661 lea rdi, [rsi + VMCPU.cpum.GstCtx]
662 mov [rbp + frm_pGstCtx], rdi
663
664 %ifdef VBOX_STRICT
665 ;
666 ; Verify template preconditions / parameters to ensure HMSVM.cpp didn't miss some state change.
667 ;
668 cmp byte [rsi + VMCPU.hm + HMCPU.fLoadSaveGuestXcr0], %2
669 mov eax, VERR_VMX_STARTVM_PRECOND_0
670 jne NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).precond_failure_return)
671
672 mov eax, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fWorldSwitcher]
673 and eax, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT
674 cmp eax, %3
675 mov eax, VERR_VMX_STARTVM_PRECOND_1
676 jne NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).precond_failure_return)
677
678 %ifdef VBOX_WITH_KERNEL_USING_XMM
679 mov eax, VERR_VMX_STARTVM_PRECOND_2
680 test byte [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fUsedFpuGuest], 1
681 %if %4 = 0
682 jnz NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).precond_failure_return)
683 %else
684 jz NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).precond_failure_return)
685
686 mov eax, VERR_VMX_STARTVM_PRECOND_3
687 cmp dword [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask], 0
688 %if %4 = 1
689 jne NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).precond_failure_return)
690 %elif %4 = 2
691 je NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).precond_failure_return)
692 %else
693 %error Invalid template parameter 4.
694 %endif
695 %endif
696 %endif
697 %endif ; VBOX_STRICT
698
699 %if %4 != 0
700 ; Save the non-volatile SSE host register state.
701 movdqa [rbp + frm_saved_xmm6 ], xmm6
702 movdqa [rbp + frm_saved_xmm7 ], xmm7
703 movdqa [rbp + frm_saved_xmm8 ], xmm8
704 movdqa [rbp + frm_saved_xmm9 ], xmm9
705 movdqa [rbp + frm_saved_xmm10], xmm10
706 movdqa [rbp + frm_saved_xmm11], xmm11
707 movdqa [rbp + frm_saved_xmm12], xmm12
708 movdqa [rbp + frm_saved_xmm13], xmm13
709 movdqa [rbp + frm_saved_xmm14], xmm14
710 movdqa [rbp + frm_saved_xmm15], xmm15
711 stmxcsr [rbp + frm_saved_mxcsr]
712
713 ; Load the guest state related to the above non-volatile and volatile SSE registers. Trashes rcx, eax and edx.
714 mov rcx, [rdi + CPUMCTX.pXStateR0]
715 %if %4 = 1 ; manual
716 movdqa xmm0, [rcx + XMM_OFF_IN_X86FXSTATE + 000h]
717 movdqa xmm1, [rcx + XMM_OFF_IN_X86FXSTATE + 010h]
718 movdqa xmm2, [rcx + XMM_OFF_IN_X86FXSTATE + 020h]
719 movdqa xmm3, [rcx + XMM_OFF_IN_X86FXSTATE + 030h]
720 movdqa xmm4, [rcx + XMM_OFF_IN_X86FXSTATE + 040h]
721 movdqa xmm5, [rcx + XMM_OFF_IN_X86FXSTATE + 050h]
722 movdqa xmm6, [rcx + XMM_OFF_IN_X86FXSTATE + 060h]
723 movdqa xmm7, [rcx + XMM_OFF_IN_X86FXSTATE + 070h]
724 movdqa xmm8, [rcx + XMM_OFF_IN_X86FXSTATE + 080h]
725 movdqa xmm9, [rcx + XMM_OFF_IN_X86FXSTATE + 090h]
726 movdqa xmm10, [rcx + XMM_OFF_IN_X86FXSTATE + 0a0h]
727 movdqa xmm11, [rcx + XMM_OFF_IN_X86FXSTATE + 0b0h]
728 movdqa xmm12, [rcx + XMM_OFF_IN_X86FXSTATE + 0c0h]
729 movdqa xmm13, [rcx + XMM_OFF_IN_X86FXSTATE + 0d0h]
730 movdqa xmm14, [rcx + XMM_OFF_IN_X86FXSTATE + 0e0h]
731 movdqa xmm15, [rcx + XMM_OFF_IN_X86FXSTATE + 0f0h]
732 ldmxcsr [rcx + X86FXSTATE.MXCSR]
733 %elif %4 = 2 ; use xrstor/xsave
734 mov eax, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask]
735 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
736 xor edx, edx
737 xrstor [rcx]
738 %else
739 %error invalid template parameter 4
740 %endif
741 %endif
742
743 %if %2 != 0
744 ; Save the host XCR0 and load the guest one if necessary.
745 ; Note! Trashes rax, rdx and rcx.
746 xor ecx, ecx
747 xgetbv ; save the host one on the stack
748 mov [rbp + frm_uHostXcr0], eax
749 mov [rbp + frm_uHostXcr0 + 4], edx
750
751 mov eax, [rdi + CPUMCTX.aXcr] ; load the guest one
752 mov edx, [rdi + CPUMCTX.aXcr + 4]
753 xor ecx, ecx ; paranoia; indicate that we must restore XCR0 (popped into ecx, thus 0)
754 xsetbv
755 %endif
756
757 ; Save host LDTR.
758 sldt word [rbp + frm_saved_ldtr]
759
760 %ifndef VMX_SKIP_TR
761 ; The host TR limit is reset to 0x67; save & restore it manually.
762 str word [rbp + frm_saved_tr]
763 %endif
764
765 %ifndef VMX_SKIP_GDTR
766 ; VT-x only saves the base of the GDTR & IDTR and resets the limit to 0xffff; we must restore the limit correctly!
767 sgdt [rbp + frm_saved_gdtr]
768 %endif
769 %ifndef VMX_SKIP_IDTR
770 sidt [rbp + frm_saved_idtr]
771 %endif
772
773 ; Load CR2 if necessary (expensive as writing CR2 is a synchronizing instruction - (bird: still expensive on 10980xe)).
774 mov rcx, qword [rdi + CPUMCTX.cr2]
775 mov rdx, cr2
776 cmp rcx, rdx
777 je .skip_cr2_write
778 mov cr2, rcx
779.skip_cr2_write:
780
781 ; Set the vmlaunch/vmresume "return" host RIP and RSP values if they've changed (unlikly).
782 ; The vmwrite isn't quite for free (on an 10980xe at least), thus we check if anything changed
783 ; before writing here.
784 lea rcx, [NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1)) wrt rip]
785 cmp rcx, [rsi + VMCPU.hm + HMCPU.u + HMCPUVMX.uHostRIP]
786 jne .write_host_rip
787.wrote_host_rip:
788 cmp rsp, [rsi + VMCPU.hm + HMCPU.u + HMCPUVMX.uHostRSP]
789 jne .write_host_rsp
790.wrote_host_rsp:
791
792 ;
793 ; Fight spectre and similar. Trashes rax, rcx, and rdx.
794 ;
795 %if %3 & (CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY) ; The eax:edx value is the same for the first two.
796 AssertCompile(MSR_IA32_PRED_CMD_F_IBPB == MSR_IA32_FLUSH_CMD_F_L1D)
797 mov eax, MSR_IA32_PRED_CMD_F_IBPB
798 xor edx, edx
799 %endif
800 %if %3 & CPUMCTX_WSF_IBPB_ENTRY ; Indirect branch barrier.
801 mov ecx, MSR_IA32_PRED_CMD
802 wrmsr
803 %endif
804 %if %3 & CPUMCTX_WSF_L1D_ENTRY ; Level 1 data cache flush.
805 mov ecx, MSR_IA32_FLUSH_CMD
806 wrmsr
807 %elif %3 & CPUMCTX_WSF_MDS_ENTRY ; MDS flushing is included in L1D_FLUSH
808 mov word [rbp + frm_MDS_seg], ds
809 verw word [rbp + frm_MDS_seg]
810 %endif
811
812 ; Resume or start VM?
813 cmp bl, 0 ; fResume
814
815 ; Load guest general purpose registers.
816 mov rax, qword [rdi + CPUMCTX.eax]
817 mov rbx, qword [rdi + CPUMCTX.ebx]
818 mov rcx, qword [rdi + CPUMCTX.ecx]
819 mov rdx, qword [rdi + CPUMCTX.edx]
820 mov rbp, qword [rdi + CPUMCTX.ebp]
821 mov rsi, qword [rdi + CPUMCTX.esi]
822 mov r8, qword [rdi + CPUMCTX.r8]
823 mov r9, qword [rdi + CPUMCTX.r9]
824 mov r10, qword [rdi + CPUMCTX.r10]
825 mov r11, qword [rdi + CPUMCTX.r11]
826 mov r12, qword [rdi + CPUMCTX.r12]
827 mov r13, qword [rdi + CPUMCTX.r13]
828 mov r14, qword [rdi + CPUMCTX.r14]
829 mov r15, qword [rdi + CPUMCTX.r15]
830 mov rdi, qword [rdi + CPUMCTX.edi]
831
832 je .vmlaunch64_launch
833
834 vmresume
835 jc NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).vmxstart64_invalid_vmcs_ptr)
836 jz NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).vmxstart64_start_failed)
837 jmp NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1)) ; here if vmresume detected a failure
838
839.vmlaunch64_launch:
840 vmlaunch
841 jc NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).vmxstart64_invalid_vmcs_ptr)
842 jz NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).vmxstart64_start_failed)
843 jmp NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1)) ; here if vmlaunch detected a failure
844
845
846; Put these two outside the normal code path as they should rarely change.
847ALIGNCODE(8)
848.write_host_rip:
849 mov [rsi + VMCPU.hm + HMCPU.u + HMCPUVMX.uHostRIP], rcx
850 mov eax, VMX_VMCS_HOST_RIP ;; @todo It is only strictly necessary to write VMX_VMCS_HOST_RIP when
851 vmwrite rax, rcx ;; the VMXVMCSINFO::pfnStartVM function changes (eventually
852 %ifdef VBOX_STRICT ;; take the Windows/SSE stuff into account then)...
853 jna NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).vmwrite_failed)
854 %endif
855 jmp .wrote_host_rip
856
857ALIGNCODE(8)
858.write_host_rsp:
859 mov [rsi + VMCPU.hm + HMCPU.u + HMCPUVMX.uHostRSP], rsp
860 mov eax, VMX_VMCS_HOST_RSP
861 vmwrite rax, rsp
862 %ifdef VBOX_STRICT
863 jna NAME(RT_CONCAT(hmR0VmxStartVmHostRIP,%1).vmwrite_failed)
864 %endif
865 jmp .wrote_host_rsp
866
867ALIGNCODE(64)
868GLOBALNAME RT_CONCAT(hmR0VmxStartVmHostRIP,%1)
869
870 ;;
871 ; Common restore logic for success and error paths. We duplicate this because we
872 ; don't want to waste writing the VINF_SUCCESS return value to the stack in the
873 ; regular code path.
874 ;
875 ; @param 1 Zero if regular return, non-zero if error return. Controls label emission.
876 ; @param 2 fLoadSaveGuestXcr0 value
877 ; @param 3 The (CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY) + CPUMCTX_WSF_IBPB_EXIT value.
878 ; The entry values are either all set or not at all, as we're too lazy to flesh out all the variants.
879 ; @param 4 The SSE saving/restoring: 0 to do nothing, 1 to do it manually, 2 to use xsave/xrstor.
880 ;
881 ; @note Important that this does not modify cbFrame or rsp.
882 %macro RESTORE_STATE_VMX 4
883 ; Restore base and limit of the IDTR & GDTR.
884 %ifndef VMX_SKIP_IDTR
885 lidt [rsp + cbFrame + frm_saved_idtr]
886 %endif
887 %ifndef VMX_SKIP_GDTR
888 lgdt [rsp + cbFrame + frm_saved_gdtr]
889 %endif
890
891 ; Save the guest state and restore the non-volatile registers. We use rax=pGstCtx here.
892 mov [rsp + cbFrame + frm_guest_rax], rax
893 mov rax, [rsp + cbFrame + frm_pGstCtx]
894
895 mov qword [rax + CPUMCTX.ebp], rbp
896 lea rbp, [rsp + cbFrame] ; re-establish the frame pointer as early as possible.
897 mov qword [rax + CPUMCTX.ecx], rcx
898 mov rcx, SPECTRE_FILLER
899 mov qword [rax + CPUMCTX.edx], rdx
900 mov rdx, [rbp + frm_guest_rax]
901 mov qword [rax + CPUMCTX.eax], rdx
902 mov rdx, rcx
903 mov qword [rax + CPUMCTX.r8], r8
904 mov r8, rcx
905 mov qword [rax + CPUMCTX.r9], r9
906 mov r9, rcx
907 mov qword [rax + CPUMCTX.r10], r10
908 mov r10, rcx
909 mov qword [rax + CPUMCTX.r11], r11
910 mov r11, rcx
911 mov qword [rax + CPUMCTX.esi], rsi
912 %ifdef ASM_CALL64_MSC
913 mov rsi, [rbp + frm_saved_rsi]
914 %else
915 mov rbx, rcx
916 %endif
917 mov qword [rax + CPUMCTX.edi], rdi
918 %ifdef ASM_CALL64_MSC
919 mov rdi, [rbp + frm_saved_rdi]
920 %else
921 mov rbx, rcx
922 %endif
923 mov qword [rax + CPUMCTX.ebx], rbx
924 mov rbx, [rbp + frm_saved_rbx]
925 mov qword [rax + CPUMCTX.r12], r12
926 mov r12, [rbp + frm_saved_r12]
927 mov qword [rax + CPUMCTX.r13], r13
928 mov r13, [rbp + frm_saved_r13]
929 mov qword [rax + CPUMCTX.r14], r14
930 mov r14, [rbp + frm_saved_r14]
931 mov qword [rax + CPUMCTX.r15], r15
932 mov r15, [rbp + frm_saved_r15]
933
934 mov rdx, cr2
935 mov qword [rax + CPUMCTX.cr2], rdx
936 mov rdx, rcx
937
938 %if %4 != 0
939 ; Save the context pointer in r8 for the SSE save/restore.
940 mov r8, rax
941 %endif
942
943 %if %3 & CPUMCTX_WSF_IBPB_EXIT
944 ; Fight spectre (trashes rax, rdx and rcx).
945 %if %1 = 0 ; Skip this in failure branch (=> guru)
946 mov ecx, MSR_IA32_PRED_CMD
947 mov eax, MSR_IA32_PRED_CMD_F_IBPB
948 xor edx, edx
949 wrmsr
950 %endif
951 %endif
952
953 %ifndef VMX_SKIP_TR
954 ; Restore TSS selector; must mark it as not busy before using ltr!
955 ; ASSUME that this is supposed to be 'BUSY' (saves 20-30 ticks on the T42p).
956 %ifndef VMX_SKIP_GDTR
957 lgdt [rbp + frm_saved_gdtr]
958 %endif
959 movzx eax, word [rbp + frm_saved_tr]
960 mov ecx, eax
961 and eax, X86_SEL_MASK_OFF_RPL ; mask away TI and RPL bits leaving only the descriptor offset
962 add rax, [rbp + frm_saved_gdtr + 2] ; eax <- GDTR.address + descriptor offset
963 and dword [rax + 4], ~RT_BIT(9) ; clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit)
964 ltr cx
965 %endif
966 movzx edx, word [rbp + frm_saved_ldtr]
967 test edx, edx
968 jz %%skip_ldt_write
969 lldt dx
970%%skip_ldt_write:
971
972 %if %1 != 0
973.return_after_vmwrite_error:
974 %endif
975 ; Restore segment registers.
976 ;POP_RELEVANT_SEGMENT_REGISTERS rax, ax - currently broken.
977
978 %if %2 != 0
979 ; Restore the host XCR0.
980 xor ecx, ecx
981 mov eax, [rbp + frm_uHostXcr0]
982 mov edx, [rbp + frm_uHostXcr0 + 4]
983 xsetbv
984 %endif
985 %endmacro ; RESTORE_STATE_VMX
986
987
988 RESTORE_STATE_VMX 0, %2, %3, %4
989 mov eax, VINF_SUCCESS
990
991.vmstart64_end:
992 %if %4 != 0
993 mov r11d, eax ; save the return code.
994
995 ; Save the guest SSE state related to non-volatile and volatile SSE registers.
996 mov rcx, [r8 + CPUMCTX.pXStateR0]
997 %if %4 = 1 ; manual
998 stmxcsr [rcx + X86FXSTATE.MXCSR]
999 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 000h], xmm0
1000 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 010h], xmm1
1001 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 020h], xmm2
1002 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 030h], xmm3
1003 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 040h], xmm4
1004 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 050h], xmm5
1005 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 060h], xmm6
1006 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 070h], xmm7
1007 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 080h], xmm8
1008 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 090h], xmm9
1009 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0a0h], xmm10
1010 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0b0h], xmm11
1011 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0c0h], xmm12
1012 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0d0h], xmm13
1013 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0e0h], xmm14
1014 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0f0h], xmm15
1015 %elif %4 = 2 ; use xrstor/xsave
1016 mov eax, [r8 + CPUMCTX.fXStateMask]
1017 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
1018 xor edx, edx
1019 xsave [rcx]
1020 %else
1021 %error invalid template parameter 4
1022 %endif
1023
1024 ; Restore the host non-volatile SSE register state.
1025 ldmxcsr [rbp + frm_saved_mxcsr]
1026 movdqa xmm6, [rbp + frm_saved_xmm6 ]
1027 movdqa xmm7, [rbp + frm_saved_xmm7 ]
1028 movdqa xmm8, [rbp + frm_saved_xmm8 ]
1029 movdqa xmm9, [rbp + frm_saved_xmm9 ]
1030 movdqa xmm10, [rbp + frm_saved_xmm10]
1031 movdqa xmm11, [rbp + frm_saved_xmm11]
1032 movdqa xmm12, [rbp + frm_saved_xmm12]
1033 movdqa xmm13, [rbp + frm_saved_xmm13]
1034 movdqa xmm14, [rbp + frm_saved_xmm14]
1035 movdqa xmm15, [rbp + frm_saved_xmm15]
1036
1037 mov eax, r11d
1038 %endif ; %4 != 0
1039
1040 lea rsp, [rbp + frm_fRFlags]
1041 popf
1042 leave
1043 ret
1044
1045 ;
1046 ; Error returns.
1047 ;
1048 %ifdef VBOX_STRICT
1049.vmwrite_failed:
1050 mov dword [rsp + cbFrame + frm_rcError], VERR_VMX_INVALID_VMCS_FIELD
1051 jz .return_after_vmwrite_error
1052 mov dword [rsp + cbFrame + frm_rcError], VERR_VMX_INVALID_VMCS_PTR
1053 jmp .return_after_vmwrite_error
1054 %endif
1055.vmxstart64_invalid_vmcs_ptr:
1056 mov dword [rsp + cbFrame + frm_rcError], VERR_VMX_INVALID_VMCS_PTR_TO_START_VM
1057 jmp .vmstart64_error_return
1058.vmxstart64_start_failed:
1059 mov dword [rsp + cbFrame + frm_rcError], VERR_VMX_UNABLE_TO_START_VM
1060.vmstart64_error_return:
1061 RESTORE_STATE_VMX 1, %2, %3, %4
1062 mov eax, [rbp + frm_rcError]
1063 jmp .vmstart64_end
1064
1065 %ifdef VBOX_STRICT
1066 ; Precondition checks failed.
1067.precond_failure_return:
1068 POP_CALLEE_PRESERVED_REGISTERS
1069 %if cbFrame != cbBaseFrame
1070 %error Bad frame size value: cbFrame, expected cbBaseFrame
1071 %endif
1072 jmp .vmstart64_end
1073 %endif
1074
1075 %undef frm_fRFlags
1076 %undef frm_pGstCtx
1077 %undef frm_uHostXcr0
1078 %undef frm_saved_gdtr
1079 %undef frm_saved_tr
1080 %undef frm_fNoRestoreXcr0
1081 %undef frm_saved_idtr
1082 %undef frm_saved_ldtr
1083 %undef frm_rcError
1084 %undef frm_guest_rax
1085 %undef cbFrame
1086ENDPROC RT_CONCAT(hmR0VmxStartVm,%1)
1087
1088%endmacro ; hmR0VmxStartVmTemplate
1089
1090%macro hmR0VmxStartVmSseTemplate 3
1091hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 0, 0 | 0 | 0 | 0 , %1
1092hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 1, 0 | 0 | 0 | 0 , %1
1093hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | 0 | 0 | 0 , %1
1094hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | 0 | 0 | 0 , %1
1095hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 0, 0 | CPUMCTX_WSF_L1D_ENTRY | 0 | 0 , %1
1096hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 1, 0 | CPUMCTX_WSF_L1D_ENTRY | 0 | 0 , %1
1097hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | 0 | 0 , %1
1098hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_SansIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | 0 | 0 , %1
1099hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 0, 0 | 0 | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1100hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 1, 0 | 0 | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1101hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | 0 | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1102hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | 0 | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1103hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 0, 0 | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1104hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 1, 0 | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1105hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1106hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_SansIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | 0 , %1
1107hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 0, 0 | 0 | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1108hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 1, 0 | 0 | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1109hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | 0 | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1110hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_SansL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | 0 | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1111hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 0, 0 | CPUMCTX_WSF_L1D_ENTRY | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1112hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 1, 0 | CPUMCTX_WSF_L1D_ENTRY | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1113hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1114hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_WithL1dEntry_SansMdsEntry_WithIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | 0 | CPUMCTX_WSF_IBPB_EXIT, %1
1115hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 0, 0 | 0 | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1116hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 1, 0 | 0 | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1117hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | 0 | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1118hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_SansL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | 0 | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1119hmR0VmxStartVmTemplate _SansXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 0, 0 | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1120hmR0VmxStartVmTemplate _WithXcr0_SansIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 1, 0 | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1121hmR0VmxStartVmTemplate _SansXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1122hmR0VmxStartVmTemplate _WithXcr0_WithIbpbEntry_WithL1dEntry_WithMdsEntry_WithIbpbExit %+ %2, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_L1D_ENTRY | CPUMCTX_WSF_MDS_ENTRY | CPUMCTX_WSF_IBPB_EXIT, %1
1123%endmacro
1124hmR0VmxStartVmSseTemplate 0,,RT_NOTHING
1125hmR0VmxStartVmSseTemplate 1,_SseManual,RT_NOTHING
1126hmR0VmxStartVmSseTemplate 2,_SseXSave,RT_NOTHING
1127
1128
1129;;
1130; Clears the MDS buffers using VERW.
1131ALIGNCODE(16)
1132BEGINPROC hmR0MdsClear
1133 SEH64_END_PROLOGUE
1134 sub xSP, xCB
1135 mov [xSP], ds
1136 verw [xSP]
1137 add xSP, xCB
1138 ret
1139ENDPROC hmR0MdsClear
1140
1141
1142;;
1143; hmR0SvmVmRun template
1144;
1145; @param 1 The suffix of the variation.
1146; @param 2 fLoadSaveGuestXcr0 value
1147; @param 3 The CPUMCTX_WSF_IBPB_ENTRY + CPUMCTX_WSF_IBPB_EXIT value.
1148; @param 4 The SSE saving/restoring: 0 to do nothing, 1 to do it manually, 2 to use xsave/xrstor.
1149; Drivers shouldn't use AVX registers without saving+loading:
1150; https://msdn.microsoft.com/en-us/library/windows/hardware/ff545910%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
1151; However the compiler docs have different idea:
1152; https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
1153; We'll go with the former for now.
1154;
1155%macro hmR0SvmVmRunTemplate 4
1156
1157;;
1158; Prepares for and executes VMRUN (32-bit and 64-bit guests).
1159;
1160; @returns VBox status code
1161; @param pVM msc:rcx,gcc:rdi The cross context VM structure (unused).
1162; @param pVCpu msc:rdx,gcc:rsi The cross context virtual CPU structure of the calling EMT.
1163; @param HCPhysVmcb msc:r8, gcc:rdx Physical address of guest VMCB.
1164;
1165ALIGNCODE(64) ; This + immediate optimizations causes serious trouble for yasm and the SEH frames: prologue -28 bytes, must be <256
1166 ; So the SEH64_XXX stuff is currently not operational.
1167BEGINPROC RT_CONCAT(hmR0SvmVmRun,%1)
1168 %ifdef VBOX_WITH_KERNEL_USING_XMM
1169 %if %4 = 0
1170 ;
1171 ; The non-saving variant will currently check the two SSE preconditions and pick
1172 ; the right variant to continue with. Later we can see if we can't manage to
1173 ; move these decisions into hmR0SvmUpdateVmRunFunction().
1174 ;
1175 %ifdef ASM_CALL64_MSC
1176 test byte [rdx + VMCPU.cpum.GstCtx + CPUMCTX.fUsedFpuGuest], 1
1177 %else
1178 test byte [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fUsedFpuGuest], 1
1179 %endif
1180 jz .save_xmm_no_need
1181 %ifdef ASM_CALL64_MSC
1182 cmp dword [rdx + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask], 0
1183 %else
1184 cmp dword [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask], 0
1185 %endif
1186 je RT_CONCAT3(hmR0SvmVmRun,%1,_SseManual)
1187 jmp RT_CONCAT3(hmR0SvmVmRun,%1,_SseXSave)
1188.save_xmm_no_need:
1189 %endif
1190 %endif
1191 push rbp
1192 SEH64_PUSH_xBP
1193 mov rbp, rsp
1194 SEH64_SET_FRAME_xBP 0
1195 pushf
1196 %assign cbFrame 30h
1197 %if %4 != 0
1198 %assign cbFrame cbFrame + 16 * 11 ; Reserve space for 10x 128-bit XMM registers and MXCSR (32-bit)
1199 %endif
1200 %assign cbBaseFrame cbFrame
1201 sub rsp, cbFrame - 8h ; We subtract 8 bytes for the above pushf
1202 SEH64_ALLOCATE_STACK cbFrame ; And we have CALLEE_PRESERVED_REGISTER_COUNT following it.
1203
1204 %define frm_fRFlags -008h
1205 %define frm_uHostXcr0 -018h ; 128-bit
1206 ;%define frm_fNoRestoreXcr0 -020h ; Non-zero if we should skip XCR0 restoring.
1207 %define frm_pGstCtx -028h ; Where we stash guest CPU context for use after the vmrun.
1208 %define frm_HCPhysVmcbHost -030h ; Where we stash HCPhysVmcbHost for the vmload after vmrun.
1209 %if %4 != 0
1210 %define frm_saved_xmm6 -040h
1211 %define frm_saved_xmm7 -050h
1212 %define frm_saved_xmm8 -060h
1213 %define frm_saved_xmm9 -070h
1214 %define frm_saved_xmm10 -080h
1215 %define frm_saved_xmm11 -090h
1216 %define frm_saved_xmm12 -0a0h
1217 %define frm_saved_xmm13 -0b0h
1218 %define frm_saved_xmm14 -0c0h
1219 %define frm_saved_xmm15 -0d0h
1220 %define frm_saved_mxcsr -0e0h
1221 %endif
1222
1223 ; Manual save and restore:
1224 ; - General purpose registers except RIP, RSP, RAX
1225 ;
1226 ; Trashed:
1227 ; - CR2 (we don't care)
1228 ; - LDTR (reset to 0)
1229 ; - DRx (presumably not changed at all)
1230 ; - DR7 (reset to 0x400)
1231
1232 ; Save all general purpose host registers.
1233 PUSH_CALLEE_PRESERVED_REGISTERS
1234 SEH64_END_PROLOGUE
1235 %if cbFrame != (cbBaseFrame + 8 * CALLEE_PRESERVED_REGISTER_COUNT)
1236 %error Bad cbFrame value
1237 %endif
1238
1239 ; Shuffle parameter registers so that r8=HCPhysVmcb and rsi=pVCpu. (rdx & rcx will soon be trashed.)
1240 %ifdef ASM_CALL64_GCC
1241 mov r8, rdx ; Put HCPhysVmcb in r8 like on MSC as rdx is trashed below.
1242 %else
1243 mov rsi, rdx ; Put pVCpu in rsi like on GCC as rdx is trashed below.
1244 ;mov rdi, rcx ; Put pVM in rdi like on GCC as rcx is trashed below.
1245 %endif
1246
1247 %ifdef VBOX_STRICT
1248 ;
1249 ; Verify template preconditions / parameters to ensure HMSVM.cpp didn't miss some state change.
1250 ;
1251 cmp byte [rsi + VMCPU.hm + HMCPU.fLoadSaveGuestXcr0], %2
1252 mov eax, VERR_SVM_VMRUN_PRECOND_0
1253 jne .failure_return
1254
1255 mov eax, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fWorldSwitcher]
1256 and eax, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT
1257 cmp eax, %3
1258 mov eax, VERR_SVM_VMRUN_PRECOND_1
1259 jne .failure_return
1260
1261 %ifdef VBOX_WITH_KERNEL_USING_XMM
1262 mov eax, VERR_SVM_VMRUN_PRECOND_2
1263 test byte [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fUsedFpuGuest], 1
1264 %if %4 = 0
1265 jnz .failure_return
1266 %else
1267 jz .failure_return
1268
1269 mov eax, VERR_SVM_VMRUN_PRECOND_3
1270 cmp dword [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask], 0
1271 %if %4 = 1
1272 jne .failure_return
1273 %elif %4 = 2
1274 je .failure_return
1275 %else
1276 %error Invalid template parameter 4.
1277 %endif
1278 %endif
1279 %endif
1280 %endif ; VBOX_STRICT
1281
1282 %if %4 != 0
1283 ; Save the non-volatile SSE host register state.
1284 movdqa [rbp + frm_saved_xmm6 ], xmm6
1285 movdqa [rbp + frm_saved_xmm7 ], xmm7
1286 movdqa [rbp + frm_saved_xmm8 ], xmm8
1287 movdqa [rbp + frm_saved_xmm9 ], xmm9
1288 movdqa [rbp + frm_saved_xmm10], xmm10
1289 movdqa [rbp + frm_saved_xmm11], xmm11
1290 movdqa [rbp + frm_saved_xmm12], xmm12
1291 movdqa [rbp + frm_saved_xmm13], xmm13
1292 movdqa [rbp + frm_saved_xmm14], xmm14
1293 movdqa [rbp + frm_saved_xmm15], xmm15
1294 stmxcsr [rbp + frm_saved_mxcsr]
1295
1296 ; Load the guest state related to the above non-volatile and volatile SSE registers. Trashes rcx, eax and edx.
1297 mov rcx, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.pXStateR0]
1298 %if %4 = 1 ; manual
1299 movdqa xmm0, [rcx + XMM_OFF_IN_X86FXSTATE + 000h]
1300 movdqa xmm1, [rcx + XMM_OFF_IN_X86FXSTATE + 010h]
1301 movdqa xmm2, [rcx + XMM_OFF_IN_X86FXSTATE + 020h]
1302 movdqa xmm3, [rcx + XMM_OFF_IN_X86FXSTATE + 030h]
1303 movdqa xmm4, [rcx + XMM_OFF_IN_X86FXSTATE + 040h]
1304 movdqa xmm5, [rcx + XMM_OFF_IN_X86FXSTATE + 050h]
1305 movdqa xmm6, [rcx + XMM_OFF_IN_X86FXSTATE + 060h]
1306 movdqa xmm7, [rcx + XMM_OFF_IN_X86FXSTATE + 070h]
1307 movdqa xmm8, [rcx + XMM_OFF_IN_X86FXSTATE + 080h]
1308 movdqa xmm9, [rcx + XMM_OFF_IN_X86FXSTATE + 090h]
1309 movdqa xmm10, [rcx + XMM_OFF_IN_X86FXSTATE + 0a0h]
1310 movdqa xmm11, [rcx + XMM_OFF_IN_X86FXSTATE + 0b0h]
1311 movdqa xmm12, [rcx + XMM_OFF_IN_X86FXSTATE + 0c0h]
1312 movdqa xmm13, [rcx + XMM_OFF_IN_X86FXSTATE + 0d0h]
1313 movdqa xmm14, [rcx + XMM_OFF_IN_X86FXSTATE + 0e0h]
1314 movdqa xmm15, [rcx + XMM_OFF_IN_X86FXSTATE + 0f0h]
1315 ldmxcsr [rcx + X86FXSTATE.MXCSR]
1316 %elif %4 = 2 ; use xrstor/xsave
1317 mov eax, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.fXStateMask]
1318 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
1319 xor edx, edx
1320 xrstor [rcx]
1321 %else
1322 %error invalid template parameter 4
1323 %endif
1324 %endif
1325
1326 %if %2 != 0
1327 ; Save the host XCR0 and load the guest one if necessary.
1328 xor ecx, ecx
1329 xgetbv ; save the host XCR0 on the stack
1330 mov [rbp + frm_uHostXcr0 + 8], rdx
1331 mov [rbp + frm_uHostXcr0 ], rax
1332
1333 mov eax, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.aXcr] ; load the guest XCR0
1334 mov edx, [rsi + VMCPU.cpum.GstCtx + CPUMCTX.aXcr + 4]
1335 xor ecx, ecx ; paranoia
1336 xsetbv
1337 %endif
1338
1339 ; Save host fs, gs, sysenter msr etc.
1340 mov rax, [rsi + VMCPU.hm + HMCPU.u + HMCPUSVM.HCPhysVmcbHost]
1341 mov qword [rbp + frm_HCPhysVmcbHost], rax ; save for the vmload after vmrun
1342 lea rsi, [rsi + VMCPU.cpum.GstCtx]
1343 mov qword [rbp + frm_pGstCtx], rsi
1344 vmsave
1345
1346 %if %3 & CPUMCTX_WSF_IBPB_ENTRY
1347 ; Fight spectre (trashes rax, rdx and rcx).
1348 mov ecx, MSR_IA32_PRED_CMD
1349 mov eax, MSR_IA32_PRED_CMD_F_IBPB
1350 xor edx, edx
1351 wrmsr
1352 %endif
1353
1354 ; Setup rax for VMLOAD.
1355 mov rax, r8 ; HCPhysVmcb (64 bits physical address; take low dword only)
1356
1357 ; Load guest general purpose registers (rax is loaded from the VMCB by VMRUN).
1358 mov rbx, qword [rsi + CPUMCTX.ebx]
1359 mov rcx, qword [rsi + CPUMCTX.ecx]
1360 mov rdx, qword [rsi + CPUMCTX.edx]
1361 mov rdi, qword [rsi + CPUMCTX.edi]
1362 mov rbp, qword [rsi + CPUMCTX.ebp]
1363 mov r8, qword [rsi + CPUMCTX.r8]
1364 mov r9, qword [rsi + CPUMCTX.r9]
1365 mov r10, qword [rsi + CPUMCTX.r10]
1366 mov r11, qword [rsi + CPUMCTX.r11]
1367 mov r12, qword [rsi + CPUMCTX.r12]
1368 mov r13, qword [rsi + CPUMCTX.r13]
1369 mov r14, qword [rsi + CPUMCTX.r14]
1370 mov r15, qword [rsi + CPUMCTX.r15]
1371 mov rsi, qword [rsi + CPUMCTX.esi]
1372
1373 ; Clear the global interrupt flag & execute sti to make sure external interrupts cause a world switch.
1374 clgi
1375 sti
1376
1377 ; Load guest FS, GS, Sysenter MSRs etc.
1378 vmload
1379
1380 ; Run the VM.
1381 vmrun
1382
1383 ; Save guest fs, gs, sysenter msr etc.
1384 vmsave
1385
1386 ; Load host fs, gs, sysenter msr etc.
1387 mov rax, [rsp + cbFrame + frm_HCPhysVmcbHost] ; load HCPhysVmcbHost (rbp is not operational yet, thus rsp)
1388 vmload
1389
1390 ; Set the global interrupt flag again, but execute cli to make sure IF=0.
1391 cli
1392 stgi
1393
1394 ; Pop pVCpu (saved above) and save the guest GPRs (sans RSP and RAX).
1395 mov rax, [rsp + cbFrame + frm_pGstCtx] ; (rbp still not operational)
1396
1397 mov qword [rax + CPUMCTX.ebp], rbp
1398 lea rbp, [rsp + cbFrame]
1399 mov qword [rax + CPUMCTX.ecx], rcx
1400 mov rcx, SPECTRE_FILLER
1401 mov qword [rax + CPUMCTX.edx], rdx
1402 mov rdx, rcx
1403 mov qword [rax + CPUMCTX.r8], r8
1404 mov r8, rcx
1405 mov qword [rax + CPUMCTX.r9], r9
1406 mov r9, rcx
1407 mov qword [rax + CPUMCTX.r10], r10
1408 mov r10, rcx
1409 mov qword [rax + CPUMCTX.r11], r11
1410 mov r11, rcx
1411 mov qword [rax + CPUMCTX.edi], rdi
1412 %ifdef ASM_CALL64_MSC
1413 mov rdi, [rbp + frm_saved_rdi]
1414 %else
1415 mov rdi, rcx
1416 %endif
1417 mov qword [rax + CPUMCTX.esi], rsi
1418 %ifdef ASM_CALL64_MSC
1419 mov rsi, [rbp + frm_saved_rsi]
1420 %else
1421 mov rsi, rcx
1422 %endif
1423 mov qword [rax + CPUMCTX.ebx], rbx
1424 mov rbx, [rbp + frm_saved_rbx]
1425 mov qword [rax + CPUMCTX.r12], r12
1426 mov r12, [rbp + frm_saved_r12]
1427 mov qword [rax + CPUMCTX.r13], r13
1428 mov r13, [rbp + frm_saved_r13]
1429 mov qword [rax + CPUMCTX.r14], r14
1430 mov r14, [rbp + frm_saved_r14]
1431 mov qword [rax + CPUMCTX.r15], r15
1432 mov r15, [rbp + frm_saved_r15]
1433
1434 %if %4 != 0
1435 ; Set r8 = &pVCpu->cpum.GstCtx; for use below when saving and restoring SSE state.
1436 mov r8, rax
1437 %endif
1438
1439 %if %3 & CPUMCTX_WSF_IBPB_EXIT
1440 ; Fight spectre (trashes rax, rdx and rcx).
1441 mov ecx, MSR_IA32_PRED_CMD
1442 mov eax, MSR_IA32_PRED_CMD_F_IBPB
1443 xor edx, edx
1444 wrmsr
1445 %endif
1446
1447 %if %2 != 0
1448 ; Restore the host xcr0.
1449 xor ecx, ecx
1450 mov rdx, [rbp + frm_uHostXcr0 + 8]
1451 mov rax, [rbp + frm_uHostXcr0]
1452 xsetbv
1453 %endif
1454
1455 %if %4 != 0
1456 ; Save the guest SSE state related to non-volatile and volatile SSE registers.
1457 mov rcx, [r8 + CPUMCTX.pXStateR0]
1458 %if %4 = 1 ; manual
1459 stmxcsr [rcx + X86FXSTATE.MXCSR]
1460 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 000h], xmm0
1461 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 010h], xmm1
1462 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 020h], xmm2
1463 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 030h], xmm3
1464 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 040h], xmm4
1465 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 050h], xmm5
1466 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 060h], xmm6
1467 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 070h], xmm7
1468 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 080h], xmm8
1469 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 090h], xmm9
1470 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0a0h], xmm10
1471 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0b0h], xmm11
1472 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0c0h], xmm12
1473 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0d0h], xmm13
1474 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0e0h], xmm14
1475 movdqa [rcx + XMM_OFF_IN_X86FXSTATE + 0f0h], xmm15
1476 %elif %4 = 2 ; use xrstor/xsave
1477 mov eax, [r8 + CPUMCTX.fXStateMask]
1478 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
1479 xor edx, edx
1480 xsave [rcx]
1481 %else
1482 %error invalid template parameter 4
1483 %endif
1484
1485 ; Restore the host non-volatile SSE register state.
1486 ldmxcsr [rbp + frm_saved_mxcsr]
1487 movdqa xmm6, [rbp + frm_saved_xmm6 ]
1488 movdqa xmm7, [rbp + frm_saved_xmm7 ]
1489 movdqa xmm8, [rbp + frm_saved_xmm8 ]
1490 movdqa xmm9, [rbp + frm_saved_xmm9 ]
1491 movdqa xmm10, [rbp + frm_saved_xmm10]
1492 movdqa xmm11, [rbp + frm_saved_xmm11]
1493 movdqa xmm12, [rbp + frm_saved_xmm12]
1494 movdqa xmm13, [rbp + frm_saved_xmm13]
1495 movdqa xmm14, [rbp + frm_saved_xmm14]
1496 movdqa xmm15, [rbp + frm_saved_xmm15]
1497 %endif ; %4 != 0
1498
1499 ; Epilogue (assumes we restored volatile registers above when saving the guest GPRs).
1500 mov eax, VINF_SUCCESS
1501 add rsp, cbFrame - 8h
1502 popf
1503 leave
1504 ret
1505
1506 %ifdef VBOX_STRICT
1507 ; Precondition checks failed.
1508.failure_return:
1509 POP_CALLEE_PRESERVED_REGISTERS
1510 %if cbFrame != cbBaseFrame
1511 %error Bad frame size value: cbFrame
1512 %endif
1513 add rsp, cbFrame - 8h
1514 popf
1515 leave
1516 ret
1517 %endif
1518
1519%undef frm_uHostXcr0
1520%undef frm_fNoRestoreXcr0
1521%undef frm_pVCpu
1522%undef frm_HCPhysVmcbHost
1523%undef cbFrame
1524ENDPROC RT_CONCAT(hmR0SvmVmRun,%1)
1525
1526%endmacro ; hmR0SvmVmRunTemplate
1527
1528;
1529; Instantiate the hmR0SvmVmRun various variations.
1530;
1531hmR0SvmVmRunTemplate _SansXcr0_SansIbpbEntry_SansIbpbExit, 0, 0, 0
1532hmR0SvmVmRunTemplate _WithXcr0_SansIbpbEntry_SansIbpbExit, 1, 0, 0
1533hmR0SvmVmRunTemplate _SansXcr0_WithIbpbEntry_SansIbpbExit, 0, CPUMCTX_WSF_IBPB_ENTRY, 0
1534hmR0SvmVmRunTemplate _WithXcr0_WithIbpbEntry_SansIbpbExit, 1, CPUMCTX_WSF_IBPB_ENTRY, 0
1535hmR0SvmVmRunTemplate _SansXcr0_SansIbpbEntry_WithIbpbExit, 0, CPUMCTX_WSF_IBPB_EXIT, 0
1536hmR0SvmVmRunTemplate _WithXcr0_SansIbpbEntry_WithIbpbExit, 1, CPUMCTX_WSF_IBPB_EXIT, 0
1537hmR0SvmVmRunTemplate _SansXcr0_WithIbpbEntry_WithIbpbExit, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT, 0
1538hmR0SvmVmRunTemplate _WithXcr0_WithIbpbEntry_WithIbpbExit, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT, 0
1539%ifdef VBOX_WITH_KERNEL_USING_XMM
1540hmR0SvmVmRunTemplate _SansXcr0_SansIbpbEntry_SansIbpbExit_SseManual, 0, 0, 1
1541hmR0SvmVmRunTemplate _WithXcr0_SansIbpbEntry_SansIbpbExit_SseManual, 1, 0, 1
1542hmR0SvmVmRunTemplate _SansXcr0_WithIbpbEntry_SansIbpbExit_SseManual, 0, CPUMCTX_WSF_IBPB_ENTRY, 1
1543hmR0SvmVmRunTemplate _WithXcr0_WithIbpbEntry_SansIbpbExit_SseManual, 1, CPUMCTX_WSF_IBPB_ENTRY, 1
1544hmR0SvmVmRunTemplate _SansXcr0_SansIbpbEntry_WithIbpbExit_SseManual, 0, CPUMCTX_WSF_IBPB_EXIT, 1
1545hmR0SvmVmRunTemplate _WithXcr0_SansIbpbEntry_WithIbpbExit_SseManual, 1, CPUMCTX_WSF_IBPB_EXIT, 1
1546hmR0SvmVmRunTemplate _SansXcr0_WithIbpbEntry_WithIbpbExit_SseManual, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT, 1
1547hmR0SvmVmRunTemplate _WithXcr0_WithIbpbEntry_WithIbpbExit_SseManual, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT, 1
1548
1549hmR0SvmVmRunTemplate _SansXcr0_SansIbpbEntry_SansIbpbExit_SseXSave, 0, 0, 2
1550hmR0SvmVmRunTemplate _WithXcr0_SansIbpbEntry_SansIbpbExit_SseXSave, 1, 0, 2
1551hmR0SvmVmRunTemplate _SansXcr0_WithIbpbEntry_SansIbpbExit_SseXSave, 0, CPUMCTX_WSF_IBPB_ENTRY, 2
1552hmR0SvmVmRunTemplate _WithXcr0_WithIbpbEntry_SansIbpbExit_SseXSave, 1, CPUMCTX_WSF_IBPB_ENTRY, 2
1553hmR0SvmVmRunTemplate _SansXcr0_SansIbpbEntry_WithIbpbExit_SseXSave, 0, CPUMCTX_WSF_IBPB_EXIT, 2
1554hmR0SvmVmRunTemplate _WithXcr0_SansIbpbEntry_WithIbpbExit_SseXSave, 1, CPUMCTX_WSF_IBPB_EXIT, 2
1555hmR0SvmVmRunTemplate _SansXcr0_WithIbpbEntry_WithIbpbExit_SseXSave, 0, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT, 2
1556hmR0SvmVmRunTemplate _WithXcr0_WithIbpbEntry_WithIbpbExit_SseXSave, 1, CPUMCTX_WSF_IBPB_ENTRY | CPUMCTX_WSF_IBPB_EXIT, 2
1557%endif
1558
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette