VirtualBox

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

Last change on this file since 67136 was 67136, checked in by vboxsync, 7 years ago

HostDrivers/Support, VMM: bugref:8864: On Linux 4.12 the GDT is mapped read-only. The writable-mapped GDT is available and is used for clearing the TSS BUSY descriptor bit and for LTR.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 60.9 KB
Line 
1; $Id: HMR0A.asm 67136 2017-05-30 07:58:21Z vboxsync $
2;; @file
3; HM - Ring-0 VMX, SVM world-switch and helper routines
4;
5
6;
7; Copyright (C) 2006-2016 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%include "VBox/asmdefs.mac"
22%include "VBox/err.mac"
23%include "VBox/vmm/hm_vmx.mac"
24%include "VBox/vmm/cpum.mac"
25%include "VBox/vmm/vm.mac"
26%include "iprt/x86.mac"
27%include "HMInternal.mac"
28
29%ifdef RT_OS_OS2 ;; @todo fix OMF support in yasm and kick nasm out completely.
30 %macro vmwrite 2,
31 int3
32 %endmacro
33 %define vmlaunch int3
34 %define vmresume int3
35 %define vmsave int3
36 %define vmload int3
37 %define vmrun int3
38 %define clgi int3
39 %define stgi int3
40 %macro invlpga 2,
41 int3
42 %endmacro
43%endif
44
45;*********************************************************************************************************************************
46;* Defined Constants And Macros *
47;*********************************************************************************************************************************
48;; The offset of the XMM registers in X86FXSTATE.
49; Use define because I'm too lazy to convert the struct.
50%define XMM_OFF_IN_X86FXSTATE 160
51
52;;
53; Determine skipping restoring of GDTR, IDTR, TR across VMX non-root operation
54;
55%ifdef RT_ARCH_AMD64
56 %define VMX_SKIP_GDTR
57 %define VMX_SKIP_TR
58 %define VBOX_SKIP_RESTORE_SEG
59 %ifdef RT_OS_DARWIN
60 ; Load the NULL selector into DS, ES, FS and GS on 64-bit darwin so we don't
61 ; risk loading a stale LDT value or something invalid.
62 %define HM_64_BIT_USE_NULL_SEL
63 ; Darwin (Mavericks) uses IDTR limit to store the CPU Id so we need to restore it always.
64 ; See @bugref{6875}.
65 %else
66 %define VMX_SKIP_IDTR
67 %endif
68%endif
69
70;; @def MYPUSHAD
71; Macro generating an equivalent to pushad
72
73;; @def MYPOPAD
74; Macro generating an equivalent to popad
75
76;; @def MYPUSHSEGS
77; Macro saving all segment registers on the stack.
78; @param 1 full width register name
79; @param 2 16-bit register name for \a 1.
80
81;; @def MYPOPSEGS
82; Macro restoring all segment registers on the stack
83; @param 1 full width register name
84; @param 2 16-bit register name for \a 1.
85
86%ifdef ASM_CALL64_GCC
87 %macro MYPUSHAD64 0
88 push r15
89 push r14
90 push r13
91 push r12
92 push rbx
93 %endmacro
94 %macro MYPOPAD64 0
95 pop rbx
96 pop r12
97 pop r13
98 pop r14
99 pop r15
100 %endmacro
101
102%else ; ASM_CALL64_MSC
103 %macro MYPUSHAD64 0
104 push r15
105 push r14
106 push r13
107 push r12
108 push rbx
109 push rsi
110 push rdi
111 %endmacro
112 %macro MYPOPAD64 0
113 pop rdi
114 pop rsi
115 pop rbx
116 pop r12
117 pop r13
118 pop r14
119 pop r15
120 %endmacro
121%endif
122
123%ifdef VBOX_SKIP_RESTORE_SEG
124 %macro MYPUSHSEGS64 2
125 %endmacro
126
127 %macro MYPOPSEGS64 2
128 %endmacro
129%else ; !VBOX_SKIP_RESTORE_SEG
130 ; trashes, rax, rdx & rcx
131 %macro MYPUSHSEGS64 2
132 %ifndef HM_64_BIT_USE_NULL_SEL
133 mov %2, es
134 push %1
135 mov %2, ds
136 push %1
137 %endif
138
139 ; Special case for FS; Windows and Linux either don't use it or restore it when leaving kernel mode, Solaris OTOH doesn't and we must save it.
140 mov ecx, MSR_K8_FS_BASE
141 rdmsr
142 push rdx
143 push rax
144 %ifndef HM_64_BIT_USE_NULL_SEL
145 push fs
146 %endif
147
148 ; Special case for GS; OSes typically use swapgs to reset the hidden base register for GS on entry into the kernel. The same happens on exit
149 mov ecx, MSR_K8_GS_BASE
150 rdmsr
151 push rdx
152 push rax
153 %ifndef HM_64_BIT_USE_NULL_SEL
154 push gs
155 %endif
156 %endmacro
157
158 ; trashes, rax, rdx & rcx
159 %macro MYPOPSEGS64 2
160 ; Note: do not step through this code with a debugger!
161 %ifndef HM_64_BIT_USE_NULL_SEL
162 xor eax, eax
163 mov ds, ax
164 mov es, ax
165 mov fs, ax
166 mov gs, ax
167 %endif
168
169 %ifndef HM_64_BIT_USE_NULL_SEL
170 pop gs
171 %endif
172 pop rax
173 pop rdx
174 mov ecx, MSR_K8_GS_BASE
175 wrmsr
176
177 %ifndef HM_64_BIT_USE_NULL_SEL
178 pop fs
179 %endif
180 pop rax
181 pop rdx
182 mov ecx, MSR_K8_FS_BASE
183 wrmsr
184 ; Now it's safe to step again
185
186 %ifndef HM_64_BIT_USE_NULL_SEL
187 pop %1
188 mov ds, %2
189 pop %1
190 mov es, %2
191 %endif
192 %endmacro
193%endif ; VBOX_SKIP_RESTORE_SEG
194
195%macro MYPUSHAD32 0
196 pushad
197%endmacro
198%macro MYPOPAD32 0
199 popad
200%endmacro
201
202%macro MYPUSHSEGS32 2
203 push ds
204 push es
205 push fs
206 push gs
207%endmacro
208%macro MYPOPSEGS32 2
209 pop gs
210 pop fs
211 pop es
212 pop ds
213%endmacro
214
215%ifdef RT_ARCH_AMD64
216 %define MYPUSHAD MYPUSHAD64
217 %define MYPOPAD MYPOPAD64
218 %define MYPUSHSEGS MYPUSHSEGS64
219 %define MYPOPSEGS MYPOPSEGS64
220%else
221 %define MYPUSHAD MYPUSHAD32
222 %define MYPOPAD MYPOPAD32
223 %define MYPUSHSEGS MYPUSHSEGS32
224 %define MYPOPSEGS MYPOPSEGS32
225%endif
226
227
228;*********************************************************************************************************************************
229;* External Symbols *
230;*********************************************************************************************************************************
231%ifdef VBOX_WITH_KERNEL_USING_XMM
232extern NAME(CPUMIsGuestFPUStateActive)
233%endif
234
235
236BEGINCODE
237
238
239;/**
240; * Restores host-state fields.
241; *
242; * @returns VBox status code
243; * @param f32RestoreHost x86: [ebp + 08h] msc: ecx gcc: edi RestoreHost flags.
244; * @param pRestoreHost x86: [ebp + 0ch] msc: rdx gcc: rsi Pointer to the RestoreHost struct.
245; */
246ALIGNCODE(16)
247BEGINPROC VMXRestoreHostState
248%ifdef RT_ARCH_AMD64
249 %ifndef ASM_CALL64_GCC
250 ; Use GCC's input registers since we'll be needing both rcx and rdx further
251 ; down with the wrmsr instruction. Use the R10 and R11 register for saving
252 ; RDI and RSI since MSC preserve the two latter registers.
253 mov r10, rdi
254 mov r11, rsi
255 mov rdi, rcx
256 mov rsi, rdx
257 %endif
258
259 test edi, VMX_RESTORE_HOST_GDTR
260 jz .test_idtr
261 lgdt [rsi + VMXRESTOREHOST.HostGdtr]
262
263.test_idtr:
264 test edi, VMX_RESTORE_HOST_IDTR
265 jz .test_ds
266 lidt [rsi + VMXRESTOREHOST.HostIdtr]
267
268.test_ds:
269 test edi, VMX_RESTORE_HOST_SEL_DS
270 jz .test_es
271 mov ax, [rsi + VMXRESTOREHOST.uHostSelDS]
272 mov ds, eax
273
274.test_es:
275 test edi, VMX_RESTORE_HOST_SEL_ES
276 jz .test_tr
277 mov ax, [rsi + VMXRESTOREHOST.uHostSelES]
278 mov es, eax
279
280.test_tr:
281 test edi, VMX_RESTORE_HOST_SEL_TR
282 jz .test_fs
283 ; When restoring the TR, we must first clear the busy flag or we'll end up faulting.
284 mov dx, [rsi + VMXRESTOREHOST.uHostSelTR]
285 mov ax, dx
286 and eax, X86_SEL_MASK_OFF_RPL ; Mask away TI and RPL bits leaving only the descriptor offset.
287 test edi, VMX_RESTORE_HOST_GDT_READ_ONLY | VMX_RESTORE_HOST_GDT_NEED_WRITABLE
288 jnz .gdt_readonly
289 add rax, qword [rsi + VMXRESTOREHOST.HostGdtr + 2] ; xAX <- descriptor offset + GDTR.pGdt.
290 and dword [rax + 4], ~RT_BIT(9) ; Clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit).
291 ltr dx
292 jmp short .test_fs
293.gdt_readonly:
294 test edi, VMX_RESTORE_HOST_GDT_NEED_WRITABLE
295 jnz .gdt_readonly_need_writable
296 mov rcx, cr0
297 mov r9, rcx
298 add rax, qword [rsi + VMXRESTOREHOST.HostGdtr + 2] ; xAX <- descriptor offset + GDTR.pGdt.
299 and rcx, ~X86_CR0_WP
300 mov cr0, rcx
301 and dword [rax + 4], ~RT_BIT(9) ; Clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit).
302 ltr dx
303 mov cr0, r9
304 jmp short .test_fs
305.gdt_readonly_need_writable:
306 add rax, qword [rsi + VMXRESTOREHOST.HostGdtrRw + 2] ; xAX <- descriptor offset + GDTR.pGdtRw.
307 and dword [rax + 4], ~RT_BIT(9) ; Clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit).
308 lgdt [rsi + VMXRESTOREHOST.HostGdtrRw]
309 ltr dx
310 lgdt [rsi + VMXRESTOREHOST.HostGdtr] ; Load the original GDT
311
312.test_fs:
313 ;
314 ; When restoring the selector values for FS and GS, we'll temporarily trash
315 ; the base address (at least the high 32-bit bits, but quite possibly the
316 ; whole base address), the wrmsr will restore it correctly. (VT-x actually
317 ; restores the base correctly when leaving guest mode, but not the selector
318 ; value, so there is little problem with interrupts being enabled prior to
319 ; this restore job.)
320 ; We'll disable ints once for both FS and GS as that's probably faster.
321 ;
322 test edi, VMX_RESTORE_HOST_SEL_FS | VMX_RESTORE_HOST_SEL_GS
323 jz .restore_success
324 pushfq
325 cli ; (see above)
326
327 test edi, VMX_RESTORE_HOST_SEL_FS
328 jz .test_gs
329 mov ax, word [rsi + VMXRESTOREHOST.uHostSelFS]
330 mov fs, eax
331 mov eax, dword [rsi + VMXRESTOREHOST.uHostFSBase] ; uHostFSBase - Lo
332 mov edx, dword [rsi + VMXRESTOREHOST.uHostFSBase + 4h] ; uHostFSBase - Hi
333 mov ecx, MSR_K8_FS_BASE
334 wrmsr
335
336.test_gs:
337 test edi, VMX_RESTORE_HOST_SEL_GS
338 jz .restore_flags
339 mov ax, word [rsi + VMXRESTOREHOST.uHostSelGS]
340 mov gs, eax
341 mov eax, dword [rsi + VMXRESTOREHOST.uHostGSBase] ; uHostGSBase - Lo
342 mov edx, dword [rsi + VMXRESTOREHOST.uHostGSBase + 4h] ; uHostGSBase - Hi
343 mov ecx, MSR_K8_GS_BASE
344 wrmsr
345
346.restore_flags:
347 popfq
348
349.restore_success:
350 mov eax, VINF_SUCCESS
351 %ifndef ASM_CALL64_GCC
352 ; Restore RDI and RSI on MSC.
353 mov rdi, r10
354 mov rsi, r11
355 %endif
356%else ; RT_ARCH_X86
357 mov eax, VERR_NOT_IMPLEMENTED
358%endif
359 ret
360ENDPROC VMXRestoreHostState
361
362
363;/**
364; * Dispatches an NMI to the host.
365; */
366ALIGNCODE(16)
367BEGINPROC VMXDispatchHostNmi
368 int 2 ; NMI is always vector 2. The IDT[2] IRQ handler cannot be anything else. See Intel spec. 6.3.1 "External Interrupts".
369 ret
370ENDPROC VMXDispatchHostNmi
371
372
373;/**
374; * Executes VMWRITE, 64-bit value.
375; *
376; * @returns VBox status code.
377; * @param idxField x86: [ebp + 08h] msc: rcx gcc: rdi VMCS index.
378; * @param u64Data x86: [ebp + 0ch] msc: rdx gcc: rsi VM field value.
379; */
380ALIGNCODE(16)
381BEGINPROC VMXWriteVmcs64
382%ifdef RT_ARCH_AMD64
383 %ifdef ASM_CALL64_GCC
384 and edi, 0ffffffffh
385 xor rax, rax
386 vmwrite rdi, rsi
387 %else
388 and ecx, 0ffffffffh
389 xor rax, rax
390 vmwrite rcx, rdx
391 %endif
392%else ; RT_ARCH_X86
393 mov ecx, [esp + 4] ; idxField
394 lea edx, [esp + 8] ; &u64Data
395 vmwrite ecx, [edx] ; low dword
396 jz .done
397 jc .done
398 inc ecx
399 xor eax, eax
400 vmwrite ecx, [edx + 4] ; high dword
401.done:
402%endif ; RT_ARCH_X86
403 jnc .valid_vmcs
404 mov eax, VERR_VMX_INVALID_VMCS_PTR
405 ret
406.valid_vmcs:
407 jnz .the_end
408 mov eax, VERR_VMX_INVALID_VMCS_FIELD
409.the_end:
410 ret
411ENDPROC VMXWriteVmcs64
412
413
414;/**
415; * Executes VMREAD, 64-bit value.
416; *
417; * @returns VBox status code.
418; * @param idxField VMCS index.
419; * @param pData Where to store VM field value.
420; */
421;DECLASM(int) VMXReadVmcs64(uint32_t idxField, uint64_t *pData);
422ALIGNCODE(16)
423BEGINPROC VMXReadVmcs64
424%ifdef RT_ARCH_AMD64
425 %ifdef ASM_CALL64_GCC
426 and edi, 0ffffffffh
427 xor rax, rax
428 vmread [rsi], rdi
429 %else
430 and ecx, 0ffffffffh
431 xor rax, rax
432 vmread [rdx], rcx
433 %endif
434%else ; RT_ARCH_X86
435 mov ecx, [esp + 4] ; idxField
436 mov edx, [esp + 8] ; pData
437 vmread [edx], ecx ; low dword
438 jz .done
439 jc .done
440 inc ecx
441 xor eax, eax
442 vmread [edx + 4], ecx ; high dword
443.done:
444%endif ; RT_ARCH_X86
445 jnc .valid_vmcs
446 mov eax, VERR_VMX_INVALID_VMCS_PTR
447 ret
448.valid_vmcs:
449 jnz .the_end
450 mov eax, VERR_VMX_INVALID_VMCS_FIELD
451.the_end:
452 ret
453ENDPROC VMXReadVmcs64
454
455
456;/**
457; * Executes VMREAD, 32-bit value.
458; *
459; * @returns VBox status code.
460; * @param idxField VMCS index.
461; * @param pu32Data Where to store VM field value.
462; */
463;DECLASM(int) VMXReadVmcs32(uint32_t idxField, uint32_t *pu32Data);
464ALIGNCODE(16)
465BEGINPROC VMXReadVmcs32
466%ifdef RT_ARCH_AMD64
467 %ifdef ASM_CALL64_GCC
468 and edi, 0ffffffffh
469 xor rax, rax
470 vmread r10, rdi
471 mov [rsi], r10d
472 %else
473 and ecx, 0ffffffffh
474 xor rax, rax
475 vmread r10, rcx
476 mov [rdx], r10d
477 %endif
478%else ; RT_ARCH_X86
479 mov ecx, [esp + 4] ; idxField
480 mov edx, [esp + 8] ; pu32Data
481 xor eax, eax
482 vmread [edx], ecx
483%endif ; RT_ARCH_X86
484 jnc .valid_vmcs
485 mov eax, VERR_VMX_INVALID_VMCS_PTR
486 ret
487.valid_vmcs:
488 jnz .the_end
489 mov eax, VERR_VMX_INVALID_VMCS_FIELD
490.the_end:
491 ret
492ENDPROC VMXReadVmcs32
493
494
495;/**
496; * Executes VMWRITE, 32-bit value.
497; *
498; * @returns VBox status code.
499; * @param idxField VMCS index.
500; * @param u32Data Where to store VM field value.
501; */
502;DECLASM(int) VMXWriteVmcs32(uint32_t idxField, uint32_t u32Data);
503ALIGNCODE(16)
504BEGINPROC VMXWriteVmcs32
505%ifdef RT_ARCH_AMD64
506 %ifdef ASM_CALL64_GCC
507 and edi, 0ffffffffh
508 and esi, 0ffffffffh
509 xor rax, rax
510 vmwrite rdi, rsi
511 %else
512 and ecx, 0ffffffffh
513 and edx, 0ffffffffh
514 xor rax, rax
515 vmwrite rcx, rdx
516 %endif
517%else ; RT_ARCH_X86
518 mov ecx, [esp + 4] ; idxField
519 mov edx, [esp + 8] ; u32Data
520 xor eax, eax
521 vmwrite ecx, edx
522%endif ; RT_ARCH_X86
523 jnc .valid_vmcs
524 mov eax, VERR_VMX_INVALID_VMCS_PTR
525 ret
526.valid_vmcs:
527 jnz .the_end
528 mov eax, VERR_VMX_INVALID_VMCS_FIELD
529.the_end:
530 ret
531ENDPROC VMXWriteVmcs32
532
533
534;/**
535; * Executes VMXON.
536; *
537; * @returns VBox status code.
538; * @param HCPhysVMXOn Physical address of VMXON structure.
539; */
540;DECLASM(int) VMXEnable(RTHCPHYS HCPhysVMXOn);
541BEGINPROC VMXEnable
542%ifdef RT_ARCH_AMD64
543 xor rax, rax
544 %ifdef ASM_CALL64_GCC
545 push rdi
546 %else
547 push rcx
548 %endif
549 vmxon [rsp]
550%else ; RT_ARCH_X86
551 xor eax, eax
552 vmxon [esp + 4]
553%endif ; RT_ARCH_X86
554 jnc .good
555 mov eax, VERR_VMX_INVALID_VMXON_PTR
556 jmp .the_end
557
558.good:
559 jnz .the_end
560 mov eax, VERR_VMX_VMXON_FAILED
561
562.the_end:
563%ifdef RT_ARCH_AMD64
564 add rsp, 8
565%endif
566 ret
567ENDPROC VMXEnable
568
569
570;/**
571; * Executes VMXOFF.
572; */
573;DECLASM(void) VMXDisable(void);
574BEGINPROC VMXDisable
575 vmxoff
576.the_end:
577 ret
578ENDPROC VMXDisable
579
580
581;/**
582; * Executes VMCLEAR.
583; *
584; * @returns VBox status code.
585; * @param HCPhysVmcs Physical address of VM control structure.
586; */
587;DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs);
588ALIGNCODE(16)
589BEGINPROC VMXClearVmcs
590%ifdef RT_ARCH_AMD64
591 xor rax, rax
592 %ifdef ASM_CALL64_GCC
593 push rdi
594 %else
595 push rcx
596 %endif
597 vmclear [rsp]
598%else ; RT_ARCH_X86
599 xor eax, eax
600 vmclear [esp + 4]
601%endif ; RT_ARCH_X86
602 jnc .the_end
603 mov eax, VERR_VMX_INVALID_VMCS_PTR
604.the_end:
605%ifdef RT_ARCH_AMD64
606 add rsp, 8
607%endif
608 ret
609ENDPROC VMXClearVmcs
610
611
612;/**
613; * Executes VMPTRLD.
614; *
615; * @returns VBox status code.
616; * @param HCPhysVmcs Physical address of VMCS structure.
617; */
618;DECLASM(int) VMXActivateVmcs(RTHCPHYS HCPhysVmcs);
619ALIGNCODE(16)
620BEGINPROC VMXActivateVmcs
621%ifdef RT_ARCH_AMD64
622 xor rax, rax
623 %ifdef ASM_CALL64_GCC
624 push rdi
625 %else
626 push rcx
627 %endif
628 vmptrld [rsp]
629%else
630 xor eax, eax
631 vmptrld [esp + 4]
632%endif
633 jnc .the_end
634 mov eax, VERR_VMX_INVALID_VMCS_PTR
635.the_end:
636%ifdef RT_ARCH_AMD64
637 add rsp, 8
638%endif
639 ret
640ENDPROC VMXActivateVmcs
641
642
643;/**
644; * Executes VMPTRST.
645; *
646; * @returns VBox status code.
647; * @param [esp + 04h] gcc:rdi msc:rcx Param 1 - First parameter - Address that will receive the current pointer.
648; */
649;DECLASM(int) VMXGetActivatedVmcs(RTHCPHYS *pVMCS);
650BEGINPROC VMXGetActivatedVmcs
651%ifdef RT_OS_OS2
652 mov eax, VERR_NOT_SUPPORTED
653 ret
654%else
655 %ifdef RT_ARCH_AMD64
656 %ifdef ASM_CALL64_GCC
657 vmptrst qword [rdi]
658 %else
659 vmptrst qword [rcx]
660 %endif
661 %else
662 vmptrst qword [esp+04h]
663 %endif
664 xor eax, eax
665.the_end:
666 ret
667%endif
668ENDPROC VMXGetActivatedVmcs
669
670;/**
671; * Invalidate a page using INVEPT.
672; @param enmFlush msc:ecx gcc:edi x86:[esp+04] Type of flush.
673; @param pDescriptor msc:edx gcc:esi x86:[esp+08] Descriptor pointer.
674; */
675;DECLASM(int) VMXR0InvEPT(VMX_FLUSH enmFlush, uint64_t *pDescriptor);
676BEGINPROC VMXR0InvEPT
677%ifdef RT_ARCH_AMD64
678 %ifdef ASM_CALL64_GCC
679 and edi, 0ffffffffh
680 xor rax, rax
681; invept rdi, qword [rsi]
682 DB 0x66, 0x0F, 0x38, 0x80, 0x3E
683 %else
684 and ecx, 0ffffffffh
685 xor rax, rax
686; invept rcx, qword [rdx]
687 DB 0x66, 0x0F, 0x38, 0x80, 0xA
688 %endif
689%else
690 mov ecx, [esp + 4]
691 mov edx, [esp + 8]
692 xor eax, eax
693; invept ecx, qword [edx]
694 DB 0x66, 0x0F, 0x38, 0x80, 0xA
695%endif
696 jnc .valid_vmcs
697 mov eax, VERR_VMX_INVALID_VMCS_PTR
698 ret
699.valid_vmcs:
700 jnz .the_end
701 mov eax, VERR_INVALID_PARAMETER
702.the_end:
703 ret
704ENDPROC VMXR0InvEPT
705
706
707;/**
708; * Invalidate a page using invvpid
709; @param enmFlush msc:ecx gcc:edi x86:[esp+04] Type of flush
710; @param pDescriptor msc:edx gcc:esi x86:[esp+08] Descriptor pointer
711; */
712;DECLASM(int) VMXR0InvVPID(VMX_FLUSH enmFlush, uint64_t *pDescriptor);
713BEGINPROC VMXR0InvVPID
714%ifdef RT_ARCH_AMD64
715 %ifdef ASM_CALL64_GCC
716 and edi, 0ffffffffh
717 xor rax, rax
718; invvpid rdi, qword [rsi]
719 DB 0x66, 0x0F, 0x38, 0x81, 0x3E
720 %else
721 and ecx, 0ffffffffh
722 xor rax, rax
723; invvpid rcx, qword [rdx]
724 DB 0x66, 0x0F, 0x38, 0x81, 0xA
725 %endif
726%else
727 mov ecx, [esp + 4]
728 mov edx, [esp + 8]
729 xor eax, eax
730; invvpid ecx, qword [edx]
731 DB 0x66, 0x0F, 0x38, 0x81, 0xA
732%endif
733 jnc .valid_vmcs
734 mov eax, VERR_VMX_INVALID_VMCS_PTR
735 ret
736.valid_vmcs:
737 jnz .the_end
738 mov eax, VERR_INVALID_PARAMETER
739.the_end:
740 ret
741ENDPROC VMXR0InvVPID
742
743
744%if GC_ARCH_BITS == 64
745;;
746; Executes INVLPGA
747;
748; @param pPageGC msc:rcx gcc:rdi x86:[esp+04] Virtual page to invalidate
749; @param uASID msc:rdx gcc:rsi x86:[esp+0C] Tagged TLB id
750;
751;DECLASM(void) SVMR0InvlpgA(RTGCPTR pPageGC, uint32_t uASID);
752BEGINPROC SVMR0InvlpgA
753%ifdef RT_ARCH_AMD64
754 %ifdef ASM_CALL64_GCC
755 mov rax, rdi
756 mov rcx, rsi
757 %else
758 mov rax, rcx
759 mov rcx, rdx
760 %endif
761%else
762 mov eax, [esp + 4]
763 mov ecx, [esp + 0Ch]
764%endif
765 invlpga [xAX], ecx
766 ret
767ENDPROC SVMR0InvlpgA
768
769%else ; GC_ARCH_BITS != 64
770;;
771; Executes INVLPGA
772;
773; @param pPageGC msc:ecx gcc:edi x86:[esp+04] Virtual page to invalidate
774; @param uASID msc:edx gcc:esi x86:[esp+08] Tagged TLB id
775;
776;DECLASM(void) SVMR0InvlpgA(RTGCPTR pPageGC, uint32_t uASID);
777BEGINPROC SVMR0InvlpgA
778%ifdef RT_ARCH_AMD64
779 %ifdef ASM_CALL64_GCC
780 movzx rax, edi
781 mov ecx, esi
782 %else
783 ; from http://www.cs.cmu.edu/~fp/courses/15213-s06/misc/asm64-handout.pdf:
784 ; ``Perhaps unexpectedly, instructions that move or generate 32-bit register
785 ; values also set the upper 32 bits of the register to zero. Consequently
786 ; there is no need for an instruction movzlq.''
787 mov eax, ecx
788 mov ecx, edx
789 %endif
790%else
791 mov eax, [esp + 4]
792 mov ecx, [esp + 8]
793%endif
794 invlpga [xAX], ecx
795 ret
796ENDPROC SVMR0InvlpgA
797
798%endif ; GC_ARCH_BITS != 64
799
800
801%ifdef VBOX_WITH_KERNEL_USING_XMM
802
803;;
804; Wrapper around vmx.pfnStartVM that preserves host XMM registers and
805; load the guest ones when necessary.
806;
807; @cproto DECLASM(int) HMR0VMXStartVMhmR0DumpDescriptorM(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu, PFNHMVMXSTARTVM pfnStartVM);
808;
809; @returns eax
810;
811; @param fResumeVM msc:rcx
812; @param pCtx msc:rdx
813; @param pVMCSCache msc:r8
814; @param pVM msc:r9
815; @param pVCpu msc:[rbp+30h] The cross context virtual CPU structure of the calling EMT.
816; @param pfnStartVM msc:[rbp+38h]
817;
818; @remarks This is essentially the same code as hmR0SVMRunWrapXMM, only the parameters differ a little bit.
819;
820; @remarks Drivers shouldn't use AVX registers without saving+loading:
821; https://msdn.microsoft.com/en-us/library/windows/hardware/ff545910%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
822; However the compiler docs have different idea:
823; https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
824; We'll go with the former for now.
825;
826; ASSUMING 64-bit and windows for now.
827;
828ALIGNCODE(16)
829BEGINPROC hmR0VMXStartVMWrapXMM
830 push xBP
831 mov xBP, xSP
832 sub xSP, 0b0h + 040h ; Don't bother optimizing the frame size.
833
834 ; spill input parameters.
835 mov [xBP + 010h], rcx ; fResumeVM
836 mov [xBP + 018h], rdx ; pCtx
837 mov [xBP + 020h], r8 ; pVMCSCache
838 mov [xBP + 028h], r9 ; pVM
839
840 ; Ask CPUM whether we've started using the FPU yet.
841 mov rcx, [xBP + 30h] ; pVCpu
842 call NAME(CPUMIsGuestFPUStateActive)
843 test al, al
844 jnz .guest_fpu_state_active
845
846 ; No need to mess with XMM registers just call the start routine and return.
847 mov r11, [xBP + 38h] ; pfnStartVM
848 mov r10, [xBP + 30h] ; pVCpu
849 mov [xSP + 020h], r10
850 mov rcx, [xBP + 010h] ; fResumeVM
851 mov rdx, [xBP + 018h] ; pCtx
852 mov r8, [xBP + 020h] ; pVMCSCache
853 mov r9, [xBP + 028h] ; pVM
854 call r11
855
856 leave
857 ret
858
859ALIGNCODE(8)
860.guest_fpu_state_active:
861 ; Save the non-volatile host XMM registers.
862 movdqa [rsp + 040h + 000h], xmm6
863 movdqa [rsp + 040h + 010h], xmm7
864 movdqa [rsp + 040h + 020h], xmm8
865 movdqa [rsp + 040h + 030h], xmm9
866 movdqa [rsp + 040h + 040h], xmm10
867 movdqa [rsp + 040h + 050h], xmm11
868 movdqa [rsp + 040h + 060h], xmm12
869 movdqa [rsp + 040h + 070h], xmm13
870 movdqa [rsp + 040h + 080h], xmm14
871 movdqa [rsp + 040h + 090h], xmm15
872 stmxcsr [rsp + 040h + 0a0h]
873
874 mov r10, [xBP + 018h] ; pCtx
875 mov eax, [r10 + CPUMCTX.fXStateMask]
876 test eax, eax
877 jz .guest_fpu_state_manually
878
879 ;
880 ; Using XSAVE to load the guest XMM, YMM and ZMM registers.
881 ;
882 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
883 xor edx, edx
884 mov r10, [r10 + CPUMCTX.pXStateR0]
885 xrstor [r10]
886
887 ; Make the call (same as in the other case ).
888 mov r11, [xBP + 38h] ; pfnStartVM
889 mov r10, [xBP + 30h] ; pVCpu
890 mov [xSP + 020h], r10
891 mov rcx, [xBP + 010h] ; fResumeVM
892 mov rdx, [xBP + 018h] ; pCtx
893 mov r8, [xBP + 020h] ; pVMCSCache
894 mov r9, [xBP + 028h] ; pVM
895 call r11
896
897 mov r11d, eax ; save return value (xsave below uses eax)
898
899 ; Save the guest XMM registers.
900 mov r10, [xBP + 018h] ; pCtx
901 mov eax, [r10 + CPUMCTX.fXStateMask]
902 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
903 xor edx, edx
904 mov r10, [r10 + CPUMCTX.pXStateR0]
905 xsave [r10]
906
907 mov eax, r11d ; restore return value.
908
909.restore_non_volatile_host_xmm_regs:
910 ; Load the non-volatile host XMM registers.
911 movdqa xmm6, [rsp + 040h + 000h]
912 movdqa xmm7, [rsp + 040h + 010h]
913 movdqa xmm8, [rsp + 040h + 020h]
914 movdqa xmm9, [rsp + 040h + 030h]
915 movdqa xmm10, [rsp + 040h + 040h]
916 movdqa xmm11, [rsp + 040h + 050h]
917 movdqa xmm12, [rsp + 040h + 060h]
918 movdqa xmm13, [rsp + 040h + 070h]
919 movdqa xmm14, [rsp + 040h + 080h]
920 movdqa xmm15, [rsp + 040h + 090h]
921 ldmxcsr [rsp + 040h + 0a0h]
922 leave
923 ret
924
925 ;
926 ; No XSAVE, load and save the guest XMM registers manually.
927 ;
928.guest_fpu_state_manually:
929 ; Load the full guest XMM register state.
930 mov r10, [r10 + CPUMCTX.pXStateR0]
931 movdqa xmm0, [r10 + XMM_OFF_IN_X86FXSTATE + 000h]
932 movdqa xmm1, [r10 + XMM_OFF_IN_X86FXSTATE + 010h]
933 movdqa xmm2, [r10 + XMM_OFF_IN_X86FXSTATE + 020h]
934 movdqa xmm3, [r10 + XMM_OFF_IN_X86FXSTATE + 030h]
935 movdqa xmm4, [r10 + XMM_OFF_IN_X86FXSTATE + 040h]
936 movdqa xmm5, [r10 + XMM_OFF_IN_X86FXSTATE + 050h]
937 movdqa xmm6, [r10 + XMM_OFF_IN_X86FXSTATE + 060h]
938 movdqa xmm7, [r10 + XMM_OFF_IN_X86FXSTATE + 070h]
939 movdqa xmm8, [r10 + XMM_OFF_IN_X86FXSTATE + 080h]
940 movdqa xmm9, [r10 + XMM_OFF_IN_X86FXSTATE + 090h]
941 movdqa xmm10, [r10 + XMM_OFF_IN_X86FXSTATE + 0a0h]
942 movdqa xmm11, [r10 + XMM_OFF_IN_X86FXSTATE + 0b0h]
943 movdqa xmm12, [r10 + XMM_OFF_IN_X86FXSTATE + 0c0h]
944 movdqa xmm13, [r10 + XMM_OFF_IN_X86FXSTATE + 0d0h]
945 movdqa xmm14, [r10 + XMM_OFF_IN_X86FXSTATE + 0e0h]
946 movdqa xmm15, [r10 + XMM_OFF_IN_X86FXSTATE + 0f0h]
947 ldmxcsr [r10 + X86FXSTATE.MXCSR]
948
949 ; Make the call (same as in the other case ).
950 mov r11, [xBP + 38h] ; pfnStartVM
951 mov r10, [xBP + 30h] ; pVCpu
952 mov [xSP + 020h], r10
953 mov rcx, [xBP + 010h] ; fResumeVM
954 mov rdx, [xBP + 018h] ; pCtx
955 mov r8, [xBP + 020h] ; pVMCSCache
956 mov r9, [xBP + 028h] ; pVM
957 call r11
958
959 ; Save the guest XMM registers.
960 mov r10, [xBP + 018h] ; pCtx
961 mov r10, [r10 + CPUMCTX.pXStateR0]
962 stmxcsr [r10 + X86FXSTATE.MXCSR]
963 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 000h], xmm0
964 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 010h], xmm1
965 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 020h], xmm2
966 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 030h], xmm3
967 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 040h], xmm4
968 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 050h], xmm5
969 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 060h], xmm6
970 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 070h], xmm7
971 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 080h], xmm8
972 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 090h], xmm9
973 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0a0h], xmm10
974 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0b0h], xmm11
975 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0c0h], xmm12
976 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0d0h], xmm13
977 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0e0h], xmm14
978 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0f0h], xmm15
979 jmp .restore_non_volatile_host_xmm_regs
980ENDPROC hmR0VMXStartVMWrapXMM
981
982;;
983; Wrapper around svm.pfnVMRun that preserves host XMM registers and
984; load the guest ones when necessary.
985;
986; @cproto DECLASM(int) hmR0SVMRunWrapXMM(RTHCPHYS pVMCBHostPhys, RTHCPHYS pVMCBPhys, PCPUMCTX pCtx, PVM pVM, PVMCPU pVCpu, PFNHMSVMVMRUN pfnVMRun);
987;
988; @returns eax
989;
990; @param pVMCBHostPhys msc:rcx
991; @param pVMCBPhys msc:rdx
992; @param pCtx msc:r8
993; @param pVM msc:r9
994; @param pVCpu msc:[rbp+30h] The cross context virtual CPU structure of the calling EMT.
995; @param pfnVMRun msc:[rbp+38h]
996;
997; @remarks This is essentially the same code as hmR0VMXStartVMWrapXMM, only the parameters differ a little bit.
998;
999; @remarks Drivers shouldn't use AVX registers without saving+loading:
1000; https://msdn.microsoft.com/en-us/library/windows/hardware/ff545910%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
1001; However the compiler docs have different idea:
1002; https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
1003; We'll go with the former for now.
1004;
1005; ASSUMING 64-bit and windows for now.
1006ALIGNCODE(16)
1007BEGINPROC hmR0SVMRunWrapXMM
1008 push xBP
1009 mov xBP, xSP
1010 sub xSP, 0b0h + 040h ; Don't bother optimizing the frame size.
1011
1012 ; spill input parameters.
1013 mov [xBP + 010h], rcx ; pVMCBHostPhys
1014 mov [xBP + 018h], rdx ; pVMCBPhys
1015 mov [xBP + 020h], r8 ; pCtx
1016 mov [xBP + 028h], r9 ; pVM
1017
1018 ; Ask CPUM whether we've started using the FPU yet.
1019 mov rcx, [xBP + 30h] ; pVCpu
1020 call NAME(CPUMIsGuestFPUStateActive)
1021 test al, al
1022 jnz .guest_fpu_state_active
1023
1024 ; No need to mess with XMM registers just call the start routine and return.
1025 mov r11, [xBP + 38h] ; pfnVMRun
1026 mov r10, [xBP + 30h] ; pVCpu
1027 mov [xSP + 020h], r10
1028 mov rcx, [xBP + 010h] ; pVMCBHostPhys
1029 mov rdx, [xBP + 018h] ; pVMCBPhys
1030 mov r8, [xBP + 020h] ; pCtx
1031 mov r9, [xBP + 028h] ; pVM
1032 call r11
1033
1034 leave
1035 ret
1036
1037ALIGNCODE(8)
1038.guest_fpu_state_active:
1039 ; Save the non-volatile host XMM registers.
1040 movdqa [rsp + 040h + 000h], xmm6
1041 movdqa [rsp + 040h + 010h], xmm7
1042 movdqa [rsp + 040h + 020h], xmm8
1043 movdqa [rsp + 040h + 030h], xmm9
1044 movdqa [rsp + 040h + 040h], xmm10
1045 movdqa [rsp + 040h + 050h], xmm11
1046 movdqa [rsp + 040h + 060h], xmm12
1047 movdqa [rsp + 040h + 070h], xmm13
1048 movdqa [rsp + 040h + 080h], xmm14
1049 movdqa [rsp + 040h + 090h], xmm15
1050 stmxcsr [rsp + 040h + 0a0h]
1051
1052 mov r10, [xBP + 020h] ; pCtx
1053 mov eax, [r10 + CPUMCTX.fXStateMask]
1054 test eax, eax
1055 jz .guest_fpu_state_manually
1056
1057 ;
1058 ; Using XSAVE.
1059 ;
1060 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
1061 xor edx, edx
1062 mov r10, [r10 + CPUMCTX.pXStateR0]
1063 xrstor [r10]
1064
1065 ; Make the call (same as in the other case ).
1066 mov r11, [xBP + 38h] ; pfnVMRun
1067 mov r10, [xBP + 30h] ; pVCpu
1068 mov [xSP + 020h], r10
1069 mov rcx, [xBP + 010h] ; pVMCBHostPhys
1070 mov rdx, [xBP + 018h] ; pVMCBPhys
1071 mov r8, [xBP + 020h] ; pCtx
1072 mov r9, [xBP + 028h] ; pVM
1073 call r11
1074
1075 mov r11d, eax ; save return value (xsave below uses eax)
1076
1077 ; Save the guest XMM registers.
1078 mov r10, [xBP + 020h] ; pCtx
1079 mov eax, [r10 + CPUMCTX.fXStateMask]
1080 and eax, CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS
1081 xor edx, edx
1082 mov r10, [r10 + CPUMCTX.pXStateR0]
1083 xsave [r10]
1084
1085 mov eax, r11d ; restore return value.
1086
1087.restore_non_volatile_host_xmm_regs:
1088 ; Load the non-volatile host XMM registers.
1089 movdqa xmm6, [rsp + 040h + 000h]
1090 movdqa xmm7, [rsp + 040h + 010h]
1091 movdqa xmm8, [rsp + 040h + 020h]
1092 movdqa xmm9, [rsp + 040h + 030h]
1093 movdqa xmm10, [rsp + 040h + 040h]
1094 movdqa xmm11, [rsp + 040h + 050h]
1095 movdqa xmm12, [rsp + 040h + 060h]
1096 movdqa xmm13, [rsp + 040h + 070h]
1097 movdqa xmm14, [rsp + 040h + 080h]
1098 movdqa xmm15, [rsp + 040h + 090h]
1099 ldmxcsr [rsp + 040h + 0a0h]
1100 leave
1101 ret
1102
1103 ;
1104 ; No XSAVE, load and save the guest XMM registers manually.
1105 ;
1106.guest_fpu_state_manually:
1107 ; Load the full guest XMM register state.
1108 mov r10, [r10 + CPUMCTX.pXStateR0]
1109 movdqa xmm0, [r10 + XMM_OFF_IN_X86FXSTATE + 000h]
1110 movdqa xmm1, [r10 + XMM_OFF_IN_X86FXSTATE + 010h]
1111 movdqa xmm2, [r10 + XMM_OFF_IN_X86FXSTATE + 020h]
1112 movdqa xmm3, [r10 + XMM_OFF_IN_X86FXSTATE + 030h]
1113 movdqa xmm4, [r10 + XMM_OFF_IN_X86FXSTATE + 040h]
1114 movdqa xmm5, [r10 + XMM_OFF_IN_X86FXSTATE + 050h]
1115 movdqa xmm6, [r10 + XMM_OFF_IN_X86FXSTATE + 060h]
1116 movdqa xmm7, [r10 + XMM_OFF_IN_X86FXSTATE + 070h]
1117 movdqa xmm8, [r10 + XMM_OFF_IN_X86FXSTATE + 080h]
1118 movdqa xmm9, [r10 + XMM_OFF_IN_X86FXSTATE + 090h]
1119 movdqa xmm10, [r10 + XMM_OFF_IN_X86FXSTATE + 0a0h]
1120 movdqa xmm11, [r10 + XMM_OFF_IN_X86FXSTATE + 0b0h]
1121 movdqa xmm12, [r10 + XMM_OFF_IN_X86FXSTATE + 0c0h]
1122 movdqa xmm13, [r10 + XMM_OFF_IN_X86FXSTATE + 0d0h]
1123 movdqa xmm14, [r10 + XMM_OFF_IN_X86FXSTATE + 0e0h]
1124 movdqa xmm15, [r10 + XMM_OFF_IN_X86FXSTATE + 0f0h]
1125 ldmxcsr [r10 + X86FXSTATE.MXCSR]
1126
1127 ; Make the call (same as in the other case ).
1128 mov r11, [xBP + 38h] ; pfnVMRun
1129 mov r10, [xBP + 30h] ; pVCpu
1130 mov [xSP + 020h], r10
1131 mov rcx, [xBP + 010h] ; pVMCBHostPhys
1132 mov rdx, [xBP + 018h] ; pVMCBPhys
1133 mov r8, [xBP + 020h] ; pCtx
1134 mov r9, [xBP + 028h] ; pVM
1135 call r11
1136
1137 ; Save the guest XMM registers.
1138 mov r10, [xBP + 020h] ; pCtx
1139 mov r10, [r10 + CPUMCTX.pXStateR0]
1140 stmxcsr [r10 + X86FXSTATE.MXCSR]
1141 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 000h], xmm0
1142 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 010h], xmm1
1143 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 020h], xmm2
1144 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 030h], xmm3
1145 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 040h], xmm4
1146 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 050h], xmm5
1147 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 060h], xmm6
1148 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 070h], xmm7
1149 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 080h], xmm8
1150 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 090h], xmm9
1151 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0a0h], xmm10
1152 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0b0h], xmm11
1153 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0c0h], xmm12
1154 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0d0h], xmm13
1155 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0e0h], xmm14
1156 movdqa [r10 + XMM_OFF_IN_X86FXSTATE + 0f0h], xmm15
1157 jmp .restore_non_volatile_host_xmm_regs
1158ENDPROC hmR0SVMRunWrapXMM
1159
1160%endif ; VBOX_WITH_KERNEL_USING_XMM
1161
1162
1163;; @def RESTORE_STATE_VM32
1164; Macro restoring essential host state and updating guest state
1165; for common host, 32-bit guest for VT-x.
1166%macro RESTORE_STATE_VM32 0
1167 ; Restore base and limit of the IDTR & GDTR.
1168 %ifndef VMX_SKIP_IDTR
1169 lidt [xSP]
1170 add xSP, xCB * 2
1171 %endif
1172 %ifndef VMX_SKIP_GDTR
1173 lgdt [xSP]
1174 add xSP, xCB * 2
1175 %endif
1176
1177 push xDI
1178 %ifndef VMX_SKIP_TR
1179 mov xDI, [xSP + xCB * 3] ; pCtx (*3 to skip the saved xDI, TR, LDTR).
1180 %else
1181 mov xDI, [xSP + xCB * 2] ; pCtx (*2 to skip the saved xDI, LDTR).
1182 %endif
1183
1184 mov [ss:xDI + CPUMCTX.eax], eax
1185 mov [ss:xDI + CPUMCTX.ebx], ebx
1186 mov [ss:xDI + CPUMCTX.ecx], ecx
1187 mov [ss:xDI + CPUMCTX.edx], edx
1188 mov [ss:xDI + CPUMCTX.esi], esi
1189 mov [ss:xDI + CPUMCTX.ebp], ebp
1190 mov xAX, cr2
1191 mov [ss:xDI + CPUMCTX.cr2], xAX
1192
1193 %ifdef RT_ARCH_AMD64
1194 pop xAX ; The guest edi we pushed above.
1195 mov dword [ss:xDI + CPUMCTX.edi], eax
1196 %else
1197 pop dword [ss:xDI + CPUMCTX.edi] ; The guest edi we pushed above.
1198 %endif
1199
1200 %ifndef VMX_SKIP_TR
1201 ; Restore TSS selector; must mark it as not busy before using ltr (!)
1202 ; ASSUME that this is supposed to be 'BUSY'. (saves 20-30 ticks on the T42p)
1203 ; @todo get rid of sgdt
1204 pop xBX ; Saved TR
1205 sub xSP, xCB * 2
1206 sgdt [xSP]
1207 mov xAX, xBX
1208 and eax, X86_SEL_MASK_OFF_RPL ; Mask away TI and RPL bits leaving only the descriptor offset.
1209 add xAX, [xSP + 2] ; eax <- GDTR.address + descriptor offset.
1210 and dword [ss:xAX + 4], ~RT_BIT(9) ; Clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit).
1211 ltr bx
1212 add xSP, xCB * 2
1213 %endif
1214
1215 pop xAX ; Saved LDTR
1216 %ifdef RT_ARCH_AMD64
1217 cmp eax, 0
1218 je %%skip_ldt_write32
1219 %endif
1220 lldt ax
1221
1222%%skip_ldt_write32:
1223 add xSP, xCB ; pCtx
1224
1225 %ifdef VMX_USE_CACHED_VMCS_ACCESSES
1226 pop xDX ; Saved pCache
1227
1228 ; Note! If we get here as a result of invalid VMCS pointer, all the following
1229 ; vmread's will fail (only eflags.cf=1 will be set) but that shouldn't cause any
1230 ; trouble only just less efficient.
1231 mov ecx, [ss:xDX + VMCSCACHE.Read.cValidEntries]
1232 cmp ecx, 0 ; Can't happen
1233 je %%no_cached_read32
1234 jmp %%cached_read32
1235
1236ALIGN(16)
1237%%cached_read32:
1238 dec xCX
1239 mov eax, [ss:xDX + VMCSCACHE.Read.aField + xCX * 4]
1240 ; Note! This leaves the high 32 bits of the cache entry unmodified!!
1241 vmread [ss:xDX + VMCSCACHE.Read.aFieldVal + xCX * 8], xAX
1242 cmp xCX, 0
1243 jnz %%cached_read32
1244%%no_cached_read32:
1245 %endif
1246
1247 ; Restore segment registers.
1248 MYPOPSEGS xAX, ax
1249
1250 ; Restore the host XCR0 if necessary.
1251 pop xCX
1252 test ecx, ecx
1253 jnz %%xcr0_after_skip
1254 pop xAX
1255 pop xDX
1256 xsetbv ; ecx is already zero.
1257%%xcr0_after_skip:
1258
1259 ; Restore general purpose registers.
1260 MYPOPAD
1261%endmacro
1262
1263
1264;;
1265; Prepares for and executes VMLAUNCH/VMRESUME (32 bits guest mode)
1266;
1267; @returns VBox status code
1268; @param fResume x86:[ebp+8], msc:rcx,gcc:rdi Whether to use vmlauch/vmresume.
1269; @param pCtx x86:[ebp+c], msc:rdx,gcc:rsi Pointer to the guest-CPU context.
1270; @param pCache x86:[ebp+10],msc:r8, gcc:rdx Pointer to the VMCS cache.
1271; @param pVM x86:[ebp+14],msc:r9, gcc:rcx The cross context VM structure.
1272; @param pVCpu x86:[ebp+18],msc:[ebp+30],gcc:r8 The cross context virtual CPU structure of the calling EMT.
1273;
1274ALIGNCODE(16)
1275BEGINPROC VMXR0StartVM32
1276 push xBP
1277 mov xBP, xSP
1278
1279 pushf
1280 cli
1281
1282 ;
1283 ; Save all general purpose host registers.
1284 ;
1285 MYPUSHAD
1286
1287 ;
1288 ; First we have to write some final guest CPU context registers.
1289 ;
1290 mov eax, VMX_VMCS_HOST_RIP
1291%ifdef RT_ARCH_AMD64
1292 lea r10, [.vmlaunch_done wrt rip]
1293 vmwrite rax, r10
1294%else
1295 mov ecx, .vmlaunch_done
1296 vmwrite eax, ecx
1297%endif
1298 ; Note: assumes success!
1299
1300 ;
1301 ; Unify input parameter registers.
1302 ;
1303%ifdef RT_ARCH_AMD64
1304 %ifdef ASM_CALL64_GCC
1305 ; fResume already in rdi
1306 ; pCtx already in rsi
1307 mov rbx, rdx ; pCache
1308 %else
1309 mov rdi, rcx ; fResume
1310 mov rsi, rdx ; pCtx
1311 mov rbx, r8 ; pCache
1312 %endif
1313%else
1314 mov edi, [ebp + 8] ; fResume
1315 mov esi, [ebp + 12] ; pCtx
1316 mov ebx, [ebp + 16] ; pCache
1317%endif
1318
1319 ;
1320 ; Save the host XCR0 and load the guest one if necessary.
1321 ; Note! Trashes rdx and rcx.
1322 ;
1323%ifdef ASM_CALL64_MSC
1324 mov rax, [xBP + 30h] ; pVCpu
1325%elifdef ASM_CALL64_GCC
1326 mov rax, r8 ; pVCpu
1327%else
1328 mov eax, [xBP + 18h] ; pVCpu
1329%endif
1330 test byte [xAX + VMCPU.hm + HMCPU.fLoadSaveGuestXcr0], 1
1331 jz .xcr0_before_skip
1332
1333 xor ecx, ecx
1334 xgetbv ; Save the host one on the stack.
1335 push xDX
1336 push xAX
1337
1338 mov eax, [xSI + CPUMCTX.aXcr] ; Load the guest one.
1339 mov edx, [xSI + CPUMCTX.aXcr + 4]
1340 xor ecx, ecx ; paranoia
1341 xsetbv
1342
1343 push 0 ; Indicate that we must restore XCR0 (popped into ecx, thus 0).
1344 jmp .xcr0_before_done
1345
1346.xcr0_before_skip:
1347 push 3fh ; indicate that we need not.
1348.xcr0_before_done:
1349
1350 ;
1351 ; Save segment registers.
1352 ; Note! Trashes rdx & rcx, so we moved it here (amd64 case).
1353 ;
1354 MYPUSHSEGS xAX, ax
1355
1356%ifdef VMX_USE_CACHED_VMCS_ACCESSES
1357 mov ecx, [xBX + VMCSCACHE.Write.cValidEntries]
1358 cmp ecx, 0
1359 je .no_cached_writes
1360 mov edx, ecx
1361 mov ecx, 0
1362 jmp .cached_write
1363
1364ALIGN(16)
1365.cached_write:
1366 mov eax, [xBX + VMCSCACHE.Write.aField + xCX * 4]
1367 vmwrite xAX, [xBX + VMCSCACHE.Write.aFieldVal + xCX * 8]
1368 inc xCX
1369 cmp xCX, xDX
1370 jl .cached_write
1371
1372 mov dword [xBX + VMCSCACHE.Write.cValidEntries], 0
1373.no_cached_writes:
1374
1375 ; Save the pCache pointer.
1376 push xBX
1377%endif
1378
1379 ; Save the pCtx pointer.
1380 push xSI
1381
1382 ; Save host LDTR.
1383 xor eax, eax
1384 sldt ax
1385 push xAX
1386
1387%ifndef VMX_SKIP_TR
1388 ; The host TR limit is reset to 0x67; save & restore it manually.
1389 str eax
1390 push xAX
1391%endif
1392
1393%ifndef VMX_SKIP_GDTR
1394 ; VT-x only saves the base of the GDTR & IDTR and resets the limit to 0xffff; we must restore the limit correctly!
1395 sub xSP, xCB * 2
1396 sgdt [xSP]
1397%endif
1398%ifndef VMX_SKIP_IDTR
1399 sub xSP, xCB * 2
1400 sidt [xSP]
1401%endif
1402
1403 ; Load CR2 if necessary (may be expensive as writing CR2 is a synchronizing instruction).
1404 mov xBX, [xSI + CPUMCTX.cr2]
1405 mov xDX, cr2
1406 cmp xBX, xDX
1407 je .skip_cr2_write32
1408 mov cr2, xBX
1409
1410.skip_cr2_write32:
1411 mov eax, VMX_VMCS_HOST_RSP
1412 vmwrite xAX, xSP
1413 ; Note: assumes success!
1414 ; Don't mess with ESP anymore!!!
1415
1416 ; Load guest general purpose registers.
1417 mov eax, [xSI + CPUMCTX.eax]
1418 mov ebx, [xSI + CPUMCTX.ebx]
1419 mov ecx, [xSI + CPUMCTX.ecx]
1420 mov edx, [xSI + CPUMCTX.edx]
1421 mov ebp, [xSI + CPUMCTX.ebp]
1422
1423 ; Resume or start VM?
1424 cmp xDI, 0 ; fResume
1425
1426 ; Load guest edi & esi.
1427 mov edi, [xSI + CPUMCTX.edi]
1428 mov esi, [xSI + CPUMCTX.esi]
1429
1430 je .vmlaunch_launch
1431
1432 vmresume
1433 jc near .vmxstart_invalid_vmcs_ptr
1434 jz near .vmxstart_start_failed
1435 jmp .vmlaunch_done; ; Here if vmresume detected a failure.
1436
1437.vmlaunch_launch:
1438 vmlaunch
1439 jc near .vmxstart_invalid_vmcs_ptr
1440 jz near .vmxstart_start_failed
1441 jmp .vmlaunch_done; ; Here if vmlaunch detected a failure.
1442
1443ALIGNCODE(16) ;; @todo YASM BUG - this alignment is wrong on darwin, it's 1 byte off.
1444.vmlaunch_done:
1445 RESTORE_STATE_VM32
1446 mov eax, VINF_SUCCESS
1447
1448.vmstart_end:
1449 popf
1450 pop xBP
1451 ret
1452
1453.vmxstart_invalid_vmcs_ptr:
1454 RESTORE_STATE_VM32
1455 mov eax, VERR_VMX_INVALID_VMCS_PTR_TO_START_VM
1456 jmp .vmstart_end
1457
1458.vmxstart_start_failed:
1459 RESTORE_STATE_VM32
1460 mov eax, VERR_VMX_UNABLE_TO_START_VM
1461 jmp .vmstart_end
1462
1463ENDPROC VMXR0StartVM32
1464
1465
1466%ifdef RT_ARCH_AMD64
1467;; @def RESTORE_STATE_VM64
1468; Macro restoring essential host state and updating guest state
1469; for 64-bit host, 64-bit guest for VT-x.
1470;
1471%macro RESTORE_STATE_VM64 0
1472 ; Restore base and limit of the IDTR & GDTR
1473 %ifndef VMX_SKIP_IDTR
1474 lidt [xSP]
1475 add xSP, xCB * 2
1476 %endif
1477 %ifndef VMX_SKIP_GDTR
1478 lgdt [xSP]
1479 add xSP, xCB * 2
1480 %endif
1481
1482 push xDI
1483 %ifndef VMX_SKIP_TR
1484 mov xDI, [xSP + xCB * 3] ; pCtx (*3 to skip the saved xDI, TR, LDTR)
1485 %else
1486 mov xDI, [xSP + xCB * 2] ; pCtx (*2 to skip the saved xDI, LDTR)
1487 %endif
1488
1489 mov qword [xDI + CPUMCTX.eax], rax
1490 mov qword [xDI + CPUMCTX.ebx], rbx
1491 mov qword [xDI + CPUMCTX.ecx], rcx
1492 mov qword [xDI + CPUMCTX.edx], rdx
1493 mov qword [xDI + CPUMCTX.esi], rsi
1494 mov qword [xDI + CPUMCTX.ebp], rbp
1495 mov qword [xDI + CPUMCTX.r8], r8
1496 mov qword [xDI + CPUMCTX.r9], r9
1497 mov qword [xDI + CPUMCTX.r10], r10
1498 mov qword [xDI + CPUMCTX.r11], r11
1499 mov qword [xDI + CPUMCTX.r12], r12
1500 mov qword [xDI + CPUMCTX.r13], r13
1501 mov qword [xDI + CPUMCTX.r14], r14
1502 mov qword [xDI + CPUMCTX.r15], r15
1503 mov rax, cr2
1504 mov qword [xDI + CPUMCTX.cr2], rax
1505
1506 pop xAX ; The guest rdi we pushed above
1507 mov qword [xDI + CPUMCTX.edi], rax
1508
1509 %ifndef VMX_SKIP_TR
1510 ; Restore TSS selector; must mark it as not busy before using ltr (!)
1511 ; ASSUME that this is supposed to be 'BUSY'. (saves 20-30 ticks on the T42p).
1512 ; @todo get rid of sgdt
1513 pop xBX ; Saved TR
1514 sub xSP, xCB * 2
1515 sgdt [xSP]
1516 mov xAX, xBX
1517 and eax, X86_SEL_MASK_OFF_RPL ; Mask away TI and RPL bits leaving only the descriptor offset.
1518 add xAX, [xSP + 2] ; eax <- GDTR.address + descriptor offset.
1519 and dword [xAX + 4], ~RT_BIT(9) ; Clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit).
1520 ltr bx
1521 add xSP, xCB * 2
1522 %endif
1523
1524 pop xAX ; Saved LDTR
1525 cmp eax, 0
1526 je %%skip_ldt_write64
1527 lldt ax
1528
1529%%skip_ldt_write64:
1530 pop xSI ; pCtx (needed in rsi by the macros below)
1531
1532 %ifdef VMX_USE_CACHED_VMCS_ACCESSES
1533 pop xDX ; Saved pCache
1534
1535 ; Note! If we get here as a result of invalid VMCS pointer, all the following
1536 ; vmread's will fail (only eflags.cf=1 will be set) but that shouldn't cause any
1537 ; trouble only just less efficient.
1538 mov ecx, [xDX + VMCSCACHE.Read.cValidEntries]
1539 cmp ecx, 0 ; Can't happen
1540 je %%no_cached_read64
1541 jmp %%cached_read64
1542
1543ALIGN(16)
1544%%cached_read64:
1545 dec xCX
1546 mov eax, [xDX + VMCSCACHE.Read.aField + xCX * 4]
1547 vmread [xDX + VMCSCACHE.Read.aFieldVal + xCX * 8], xAX
1548 cmp xCX, 0
1549 jnz %%cached_read64
1550%%no_cached_read64:
1551 %endif
1552
1553 ; Restore segment registers.
1554 MYPOPSEGS xAX, ax
1555
1556 ; Restore the host XCR0 if necessary.
1557 pop xCX
1558 test ecx, ecx
1559 jnz %%xcr0_after_skip
1560 pop xAX
1561 pop xDX
1562 xsetbv ; ecx is already zero.
1563%%xcr0_after_skip:
1564
1565 ; Restore general purpose registers.
1566 MYPOPAD
1567%endmacro
1568
1569
1570;;
1571; Prepares for and executes VMLAUNCH/VMRESUME (64 bits guest mode)
1572;
1573; @returns VBox status code
1574; @param fResume msc:rcx, gcc:rdi Whether to use vmlauch/vmresume.
1575; @param pCtx msc:rdx, gcc:rsi Pointer to the guest-CPU context.
1576; @param pCache msc:r8, gcc:rdx Pointer to the VMCS cache.
1577; @param pVM msc:r9, gcc:rcx The cross context VM structure.
1578; @param pVCpu msc:[ebp+30], gcc:r8 The cross context virtual CPU structure of the calling EMT.
1579;
1580ALIGNCODE(16)
1581BEGINPROC VMXR0StartVM64
1582 push xBP
1583 mov xBP, xSP
1584
1585 pushf
1586 cli
1587
1588 ; Save all general purpose host registers.
1589 MYPUSHAD
1590
1591 ; First we have to save some final CPU context registers.
1592 lea r10, [.vmlaunch64_done wrt rip]
1593 mov rax, VMX_VMCS_HOST_RIP ; Return address (too difficult to continue after VMLAUNCH?).
1594 vmwrite rax, r10
1595 ; Note: assumes success!
1596
1597 ;
1598 ; Unify the input parameter registers.
1599 ;
1600%ifdef ASM_CALL64_GCC
1601 ; fResume already in rdi
1602 ; pCtx already in rsi
1603 mov rbx, rdx ; pCache
1604%else
1605 mov rdi, rcx ; fResume
1606 mov rsi, rdx ; pCtx
1607 mov rbx, r8 ; pCache
1608%endif
1609
1610 ;
1611 ; Save the host XCR0 and load the guest one if necessary.
1612 ; Note! Trashes rdx and rcx.
1613 ;
1614%ifdef ASM_CALL64_MSC
1615 mov rax, [xBP + 30h] ; pVCpu
1616%else
1617 mov rax, r8 ; pVCpu
1618%endif
1619 test byte [xAX + VMCPU.hm + HMCPU.fLoadSaveGuestXcr0], 1
1620 jz .xcr0_before_skip
1621
1622 xor ecx, ecx
1623 xgetbv ; Save the host one on the stack.
1624 push xDX
1625 push xAX
1626
1627 mov eax, [xSI + CPUMCTX.aXcr] ; Load the guest one.
1628 mov edx, [xSI + CPUMCTX.aXcr + 4]
1629 xor ecx, ecx ; paranoia
1630 xsetbv
1631
1632 push 0 ; Indicate that we must restore XCR0 (popped into ecx, thus 0).
1633 jmp .xcr0_before_done
1634
1635.xcr0_before_skip:
1636 push 3fh ; indicate that we need not.
1637.xcr0_before_done:
1638
1639 ;
1640 ; Save segment registers.
1641 ; Note! Trashes rdx & rcx, so we moved it here (amd64 case).
1642 ;
1643 MYPUSHSEGS xAX, ax
1644
1645%ifdef VMX_USE_CACHED_VMCS_ACCESSES
1646 mov ecx, [xBX + VMCSCACHE.Write.cValidEntries]
1647 cmp ecx, 0
1648 je .no_cached_writes
1649 mov edx, ecx
1650 mov ecx, 0
1651 jmp .cached_write
1652
1653ALIGN(16)
1654.cached_write:
1655 mov eax, [xBX + VMCSCACHE.Write.aField + xCX * 4]
1656 vmwrite xAX, [xBX + VMCSCACHE.Write.aFieldVal + xCX * 8]
1657 inc xCX
1658 cmp xCX, xDX
1659 jl .cached_write
1660
1661 mov dword [xBX + VMCSCACHE.Write.cValidEntries], 0
1662.no_cached_writes:
1663
1664 ; Save the pCache pointer.
1665 push xBX
1666%endif
1667
1668 ; Save the pCtx pointer.
1669 push xSI
1670
1671 ; Save host LDTR.
1672 xor eax, eax
1673 sldt ax
1674 push xAX
1675
1676%ifndef VMX_SKIP_TR
1677 ; The host TR limit is reset to 0x67; save & restore it manually.
1678 str eax
1679 push xAX
1680%endif
1681
1682%ifndef VMX_SKIP_GDTR
1683 ; VT-x only saves the base of the GDTR & IDTR and resets the limit to 0xffff; we must restore the limit correctly!
1684 sub xSP, xCB * 2
1685 sgdt [xSP]
1686%endif
1687%ifndef VMX_SKIP_IDTR
1688 sub xSP, xCB * 2
1689 sidt [xSP]
1690%endif
1691
1692 ; Load CR2 if necessary (may be expensive as writing CR2 is a synchronizing instruction).
1693 mov rbx, qword [xSI + CPUMCTX.cr2]
1694 mov rdx, cr2
1695 cmp rbx, rdx
1696 je .skip_cr2_write
1697 mov cr2, rbx
1698
1699.skip_cr2_write:
1700 mov eax, VMX_VMCS_HOST_RSP
1701 vmwrite xAX, xSP
1702 ; Note: assumes success!
1703 ; Don't mess with ESP anymore!!!
1704
1705 ; Load guest general purpose registers.
1706 mov rax, qword [xSI + CPUMCTX.eax]
1707 mov rbx, qword [xSI + CPUMCTX.ebx]
1708 mov rcx, qword [xSI + CPUMCTX.ecx]
1709 mov rdx, qword [xSI + CPUMCTX.edx]
1710 mov rbp, qword [xSI + CPUMCTX.ebp]
1711 mov r8, qword [xSI + CPUMCTX.r8]
1712 mov r9, qword [xSI + CPUMCTX.r9]
1713 mov r10, qword [xSI + CPUMCTX.r10]
1714 mov r11, qword [xSI + CPUMCTX.r11]
1715 mov r12, qword [xSI + CPUMCTX.r12]
1716 mov r13, qword [xSI + CPUMCTX.r13]
1717 mov r14, qword [xSI + CPUMCTX.r14]
1718 mov r15, qword [xSI + CPUMCTX.r15]
1719
1720 ; Resume or start VM?
1721 cmp xDI, 0 ; fResume
1722
1723 ; Load guest rdi & rsi.
1724 mov rdi, qword [xSI + CPUMCTX.edi]
1725 mov rsi, qword [xSI + CPUMCTX.esi]
1726
1727 je .vmlaunch64_launch
1728
1729 vmresume
1730 jc near .vmxstart64_invalid_vmcs_ptr
1731 jz near .vmxstart64_start_failed
1732 jmp .vmlaunch64_done; ; Here if vmresume detected a failure.
1733
1734.vmlaunch64_launch:
1735 vmlaunch
1736 jc near .vmxstart64_invalid_vmcs_ptr
1737 jz near .vmxstart64_start_failed
1738 jmp .vmlaunch64_done; ; Here if vmlaunch detected a failure.
1739
1740ALIGNCODE(16)
1741.vmlaunch64_done:
1742 RESTORE_STATE_VM64
1743 mov eax, VINF_SUCCESS
1744
1745.vmstart64_end:
1746 popf
1747 pop xBP
1748 ret
1749
1750.vmxstart64_invalid_vmcs_ptr:
1751 RESTORE_STATE_VM64
1752 mov eax, VERR_VMX_INVALID_VMCS_PTR_TO_START_VM
1753 jmp .vmstart64_end
1754
1755.vmxstart64_start_failed:
1756 RESTORE_STATE_VM64
1757 mov eax, VERR_VMX_UNABLE_TO_START_VM
1758 jmp .vmstart64_end
1759ENDPROC VMXR0StartVM64
1760%endif ; RT_ARCH_AMD64
1761
1762
1763;;
1764; Prepares for and executes VMRUN (32 bits guests)
1765;
1766; @returns VBox status code
1767; @param HCPhysVMCB Physical address of host VMCB.
1768; @param HCPhysVMCB Physical address of guest VMCB.
1769; @param pCtx Pointer to the guest CPU-context.
1770; @param pVM msc:r9, gcc:rcx The cross context VM structure.
1771; @param pVCpu msc:[rsp+28],gcc:r8 The cross context virtual CPU structure of the calling EMT.
1772;
1773ALIGNCODE(16)
1774BEGINPROC SVMR0VMRun
1775%ifdef RT_ARCH_AMD64 ; fake a cdecl stack frame
1776 %ifdef ASM_CALL64_GCC
1777 push r8
1778 push rcx
1779 push rdx
1780 push rsi
1781 push rdi
1782 %else
1783 mov rax, [rsp + 28h]
1784 push rax ; pVCpu
1785 push r9 ; pVM
1786 push r8 ; pCtx
1787 push rdx ; HCPHYSGuestVMCB
1788 push rcx ; HCPhysHostVMCB
1789 %endif
1790 push 0
1791%endif
1792 push xBP
1793 mov xBP, xSP
1794 pushf
1795
1796 ;
1797 ; Save all general purpose host registers.
1798 ;
1799 MYPUSHAD
1800
1801 ;
1802 ; Load pCtx into xSI.
1803 ;
1804 mov xSI, [xBP + xCB * 2 + RTHCPHYS_CB * 2] ; pCtx
1805
1806 ;
1807 ; Save the host XCR0 and load the guest one if necessary.
1808 ;
1809 mov xAX, [xBP + xCB * 2 + RTHCPHYS_CB * 2 + xCB * 2] ; pVCpu
1810 test byte [xAX + VMCPU.hm + HMCPU.fLoadSaveGuestXcr0], 1
1811 jz .xcr0_before_skip
1812
1813 xor ecx, ecx
1814 xgetbv ; Save the host one on the stack.
1815 push xDX
1816 push xAX
1817
1818 mov xSI, [xBP + xCB * 2 + RTHCPHYS_CB * 2] ; pCtx
1819 mov eax, [xSI + CPUMCTX.aXcr] ; Load the guest one.
1820 mov edx, [xSI + CPUMCTX.aXcr + 4]
1821 xor ecx, ecx ; paranoia
1822 xsetbv
1823
1824 push 0 ; Indicate that we must restore XCR0 (popped into ecx, thus 0).
1825 jmp .xcr0_before_done
1826
1827.xcr0_before_skip:
1828 push 3fh ; indicate that we need not.
1829.xcr0_before_done:
1830
1831 ;
1832 ; Save guest CPU-context pointer for simplifying saving of the GPRs afterwards.
1833 ;
1834 push xSI
1835
1836 ; Save host fs, gs, sysenter msr etc.
1837 mov xAX, [xBP + xCB * 2] ; pVMCBHostPhys (64 bits physical address; x86: take low dword only)
1838 push xAX ; save for the vmload after vmrun
1839 vmsave
1840
1841 ; Setup xAX for VMLOAD.
1842 mov xAX, [xBP + xCB * 2 + RTHCPHYS_CB] ; pVMCBPhys (64 bits physical address; take low dword only)
1843
1844 ; Load guest general purpose registers.
1845 ; eax is loaded from the VMCB by VMRUN.
1846 mov ebx, [xSI + CPUMCTX.ebx]
1847 mov ecx, [xSI + CPUMCTX.ecx]
1848 mov edx, [xSI + CPUMCTX.edx]
1849 mov edi, [xSI + CPUMCTX.edi]
1850 mov ebp, [xSI + CPUMCTX.ebp]
1851 mov esi, [xSI + CPUMCTX.esi]
1852
1853 ; Clear the global interrupt flag & execute sti to make sure external interrupts cause a world switch.
1854 clgi
1855 sti
1856
1857 ; Load guest fs, gs, sysenter msr etc.
1858 vmload
1859 ; Run the VM.
1860 vmrun
1861
1862 ; eax is in the VMCB already; we can use it here.
1863
1864 ; Save guest fs, gs, sysenter msr etc.
1865 vmsave
1866
1867 ; Load host fs, gs, sysenter msr etc.
1868 pop xAX ; Pushed above
1869 vmload
1870
1871 ; Set the global interrupt flag again, but execute cli to make sure IF=0.
1872 cli
1873 stgi
1874
1875 ;
1876 ; Pop the context pointer (pushed above) and save the guest GPRs (sans RSP and RAX).
1877 ;
1878 pop xAX
1879
1880 mov [ss:xAX + CPUMCTX.ebx], ebx
1881 mov [ss:xAX + CPUMCTX.ecx], ecx
1882 mov [ss:xAX + CPUMCTX.edx], edx
1883 mov [ss:xAX + CPUMCTX.esi], esi
1884 mov [ss:xAX + CPUMCTX.edi], edi
1885 mov [ss:xAX + CPUMCTX.ebp], ebp
1886
1887 ;
1888 ; Restore the host xcr0 if necessary.
1889 ;
1890 pop xCX
1891 test ecx, ecx
1892 jnz .xcr0_after_skip
1893 pop xAX
1894 pop xDX
1895 xsetbv ; ecx is already zero.
1896.xcr0_after_skip:
1897
1898 ;
1899 ; Restore host general purpose registers.
1900 ;
1901 MYPOPAD
1902
1903 mov eax, VINF_SUCCESS
1904
1905 popf
1906 pop xBP
1907%ifdef RT_ARCH_AMD64
1908 add xSP, 6*xCB
1909%endif
1910 ret
1911ENDPROC SVMR0VMRun
1912
1913
1914%ifdef RT_ARCH_AMD64
1915;;
1916; Prepares for and executes VMRUN (64 bits guests)
1917;
1918; @returns VBox status code
1919; @param HCPhysVMCB Physical address of host VMCB.
1920; @param HCPhysVMCB Physical address of guest VMCB.
1921; @param pCtx Pointer to the guest-CPU context.
1922; @param pVM msc:r9, gcc:rcx The cross context VM structure.
1923; @param pVCpu msc:[rsp+28],gcc:r8 The cross context virtual CPU structure of the calling EMT.
1924;
1925ALIGNCODE(16)
1926BEGINPROC SVMR0VMRun64
1927 ; Fake a cdecl stack frame
1928 %ifdef ASM_CALL64_GCC
1929 push r8
1930 push rcx
1931 push rdx
1932 push rsi
1933 push rdi
1934 %else
1935 mov rax, [rsp + 28h]
1936 push rax ; rbp + 30h pVCpu
1937 push r9 ; rbp + 28h pVM
1938 push r8 ; rbp + 20h pCtx
1939 push rdx ; rbp + 18h HCPHYSGuestVMCB
1940 push rcx ; rbp + 10h HCPhysHostVMCB
1941 %endif
1942 push 0 ; rbp + 08h "fake ret addr"
1943 push rbp ; rbp + 00h
1944 mov rbp, rsp
1945 pushf
1946
1947 ; Manual save and restore:
1948 ; - General purpose registers except RIP, RSP, RAX
1949 ;
1950 ; Trashed:
1951 ; - CR2 (we don't care)
1952 ; - LDTR (reset to 0)
1953 ; - DRx (presumably not changed at all)
1954 ; - DR7 (reset to 0x400)
1955 ;
1956
1957 ;
1958 ; Save all general purpose host registers.
1959 ;
1960 MYPUSHAD
1961
1962 ;
1963 ; Load pCtx into xSI.
1964 ;
1965 mov xSI, [rbp + xCB * 2 + RTHCPHYS_CB * 2]
1966
1967 ;
1968 ; Save the host XCR0 and load the guest one if necessary.
1969 ;
1970 mov rax, [xBP + 30h] ; pVCpu
1971 test byte [xAX + VMCPU.hm + HMCPU.fLoadSaveGuestXcr0], 1
1972 jz .xcr0_before_skip
1973
1974 xor ecx, ecx
1975 xgetbv ; Save the host one on the stack.
1976 push xDX
1977 push xAX
1978
1979 mov xSI, [xBP + xCB * 2 + RTHCPHYS_CB * 2] ; pCtx
1980 mov eax, [xSI + CPUMCTX.aXcr] ; Load the guest one.
1981 mov edx, [xSI + CPUMCTX.aXcr + 4]
1982 xor ecx, ecx ; paranoia
1983 xsetbv
1984
1985 push 0 ; Indicate that we must restore XCR0 (popped into ecx, thus 0).
1986 jmp .xcr0_before_done
1987
1988.xcr0_before_skip:
1989 push 3fh ; indicate that we need not.
1990.xcr0_before_done:
1991
1992 ;
1993 ; Save guest CPU-context pointer for simplifying saving of the GPRs afterwards.
1994 ;
1995 push rsi
1996
1997 ;
1998 ; Save host fs, gs, sysenter msr etc.
1999 ;
2000 mov rax, [rbp + xCB * 2] ; pVMCBHostPhys (64 bits physical address; x86: take low dword only)
2001 push rax ; Save for the vmload after vmrun
2002 vmsave
2003
2004 ; Setup rax for VMLOAD.
2005 mov rax, [rbp + xCB * 2 + RTHCPHYS_CB] ; pVMCBPhys (64 bits physical address; take low dword only)
2006
2007 ; Load guest general purpose registers.
2008 ; rax is loaded from the VMCB by VMRUN.
2009 mov rbx, qword [xSI + CPUMCTX.ebx]
2010 mov rcx, qword [xSI + CPUMCTX.ecx]
2011 mov rdx, qword [xSI + CPUMCTX.edx]
2012 mov rdi, qword [xSI + CPUMCTX.edi]
2013 mov rbp, qword [xSI + CPUMCTX.ebp]
2014 mov r8, qword [xSI + CPUMCTX.r8]
2015 mov r9, qword [xSI + CPUMCTX.r9]
2016 mov r10, qword [xSI + CPUMCTX.r10]
2017 mov r11, qword [xSI + CPUMCTX.r11]
2018 mov r12, qword [xSI + CPUMCTX.r12]
2019 mov r13, qword [xSI + CPUMCTX.r13]
2020 mov r14, qword [xSI + CPUMCTX.r14]
2021 mov r15, qword [xSI + CPUMCTX.r15]
2022 mov rsi, qword [xSI + CPUMCTX.esi]
2023
2024 ; Clear the global interrupt flag & execute sti to make sure external interrupts cause a world switch.
2025 clgi
2026 sti
2027
2028 ; Load guest fs, gs, sysenter msr etc.
2029 vmload
2030 ; Run the VM.
2031 vmrun
2032
2033 ; rax is in the VMCB already; we can use it here.
2034
2035 ; Save guest fs, gs, sysenter msr etc.
2036 vmsave
2037
2038 ;
2039 ; Load host fs, gs, sysenter msr etc.
2040 ;
2041 pop rax ; pushed above
2042 vmload
2043
2044 ;
2045 ; Set the global interrupt flag again, but execute cli to make sure IF=0.
2046 ;
2047 cli
2048 stgi
2049
2050 ;
2051 ; Pop the context pointer (pushed above) and save the guest GPRs (sans RSP and RAX).
2052 ;
2053 pop rax
2054
2055 mov qword [rax + CPUMCTX.ebx], rbx
2056 mov qword [rax + CPUMCTX.ecx], rcx
2057 mov qword [rax + CPUMCTX.edx], rdx
2058 mov qword [rax + CPUMCTX.esi], rsi
2059 mov qword [rax + CPUMCTX.edi], rdi
2060 mov qword [rax + CPUMCTX.ebp], rbp
2061 mov qword [rax + CPUMCTX.r8], r8
2062 mov qword [rax + CPUMCTX.r9], r9
2063 mov qword [rax + CPUMCTX.r10], r10
2064 mov qword [rax + CPUMCTX.r11], r11
2065 mov qword [rax + CPUMCTX.r12], r12
2066 mov qword [rax + CPUMCTX.r13], r13
2067 mov qword [rax + CPUMCTX.r14], r14
2068 mov qword [rax + CPUMCTX.r15], r15
2069
2070 ;
2071 ; Restore the host xcr0 if necessary.
2072 ;
2073 pop xCX
2074 test ecx, ecx
2075 jnz .xcr0_after_skip
2076 pop xAX
2077 pop xDX
2078 xsetbv ; ecx is already zero.
2079.xcr0_after_skip:
2080
2081 ;
2082 ; Restore host general purpose registers.
2083 ;
2084 MYPOPAD
2085
2086 mov eax, VINF_SUCCESS
2087
2088 popf
2089 pop rbp
2090 add rsp, 6 * xCB
2091 ret
2092ENDPROC SVMR0VMRun64
2093%endif ; RT_ARCH_AMD64
2094
Note: See TracBrowser for help on using the repository browser.

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