VirtualBox

source: vbox/trunk/src/VBox/VMM/include/CPUMInternal.mac@ 101549

Last change on this file since 101549 was 100935, checked in by vboxsync, 15 months ago

VMM: bugref:10498 bugref:10318: Implemented basic MTRR reporting and storage, primarily to make progress with nested Hyper-V.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.2 KB
Line 
1; $Id: CPUMInternal.mac 100935 2023-08-22 09:30:06Z vboxsync $
2;; @file
3; CPUM - Internal header file (asm).
4;
5
6;
7; Copyright (C) 2006-2023 Oracle and/or its affiliates.
8;
9; This file is part of VirtualBox base platform packages, as
10; available from https://www.virtualbox.org.
11;
12; This program is free software; you can redistribute it and/or
13; modify it under the terms of the GNU General Public License
14; as published by the Free Software Foundation, in version 3 of the
15; License.
16;
17; This program is distributed in the hope that it will be useful, but
18; WITHOUT ANY WARRANTY; without even the implied warranty of
19; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20; General Public License for more details.
21;
22; You should have received a copy of the GNU General Public License
23; along with this program; if not, see <https://www.gnu.org/licenses>.
24;
25; SPDX-License-Identifier: GPL-3.0-only
26;
27
28%include "VBox/asmdefs.mac"
29%include "VBox/vmm/cpum.mac"
30
31;; Check sanity.
32%ifdef VBOX_WITH_KERNEL_USING_XMM
33 %ifndef IN_RING0
34 %error "What? We've got code assuming VBOX_WITH_KERNEL_USING_XMM is only defined in ring-0!"
35 %endif
36%endif
37
38;; For numeric expressions
39%ifdef RT_ARCH_AMD64
40 %define CPUM_IS_AMD64 1
41%else
42 %define CPUM_IS_AMD64 0
43%endif
44
45
46;;
47; CPU info
48struc CPUMINFO
49 .cMsrRanges resd 1 ; uint32_t
50 .fMsrMask resd 1 ; uint32_t
51 .fMxCsrMask resd 1 ; uint32_t
52 .cCpuIdLeaves resd 1 ; uint32_t
53 .iFirstExtCpuIdLeaf resd 1 ; uint32_t
54 .enmUnknownCpuIdMethod resd 1 ; CPUMUNKNOWNCPUID
55 .DefCpuId resb CPUMCPUID_size ; CPUMCPUID
56 .uScalableBusFreq resq 1 ; uint64_t
57 .paMsrRangesR3 RTR3PTR_RES 1 ; R3PTRTYPE(PCPUMMSRRANGE)
58 .paCpuIdLeavesR3 RTR3PTR_RES 1 ; R3PTRTYPE(PCPUMCPUIDLEAF)
59 .aCpuIdLeaves resb 256*32
60 .aMsrRanges resb 8192*128
61endstruc
62
63
64%define CPUM_USED_FPU_HOST RT_BIT(0)
65%define CPUM_USED_FPU_GUEST RT_BIT(10)
66%define CPUM_USED_FPU_SINCE_REM RT_BIT(1)
67%define CPUM_USED_MANUAL_XMM_RESTORE RT_BIT(2)
68%define CPUM_USE_SYSENTER RT_BIT(3)
69%define CPUM_USE_SYSCALL RT_BIT(4)
70%define CPUM_USE_DEBUG_REGS_HOST RT_BIT(5)
71%define CPUM_USED_DEBUG_REGS_HOST RT_BIT(6)
72%define CPUM_USE_DEBUG_REGS_HYPER RT_BIT(7)
73%define CPUM_USED_DEBUG_REGS_HYPER RT_BIT(8)
74%define CPUM_USED_DEBUG_REGS_GUEST RT_BIT(9)
75%define CPUM_USE_FFXSR_LEAKY RT_BIT(19)
76%define CPUM_USE_SUPPORTS_LONGMODE RT_BIT(20)
77
78
79struc CPUM
80 ;...
81 .fHostUseFlags resd 1
82
83 ; CR4 masks
84 .CR4.AndMask resd 1
85 .CR4.OrMask resd 1
86 .u8PortableCpuIdLevel resb 1
87 .fPendingRestore resb 1
88 .fMtrrRead resb 1
89 .fMtrrWrite resb 1
90
91 alignb 8
92 .fXStateGuestMask resq 1
93 .fXStateHostMask resq 1
94
95 alignb 64
96 .HostFeatures resb 48
97 .GuestFeatures resb 48
98 .GuestInfo resb CPUMINFO_size
99
100 ; Patch manager saved state compatability CPUID leaf arrays
101 .aGuestCpuIdPatmStd resb 16*6
102 .aGuestCpuIdPatmExt resb 16*10
103 .aGuestCpuIdPatmCentaur resb 16*4
104
105 alignb 8
106 .cMsrWrites resq 1
107 .cMsrWritesToIgnoredBits resq 1
108 .cMsrWritesRaiseGp resq 1
109 .cMsrWritesUnknown resq 1
110 .cMsrReads resq 1
111 .cMsrReadsRaiseGp resq 1
112 .cMsrReadsUnknown resq 1
113endstruc
114
115struc CPUMCPU
116 ;
117 ; Guest context state
118 ;
119 .Guest resq 0
120 .Guest.eax resq 1
121 .Guest.ecx resq 1
122 .Guest.edx resq 1
123 .Guest.ebx resq 1
124 .Guest.esp resq 1
125 .Guest.ebp resq 1
126 .Guest.esi resq 1
127 .Guest.edi resq 1
128 .Guest.r8 resq 1
129 .Guest.r9 resq 1
130 .Guest.r10 resq 1
131 .Guest.r11 resq 1
132 .Guest.r12 resq 1
133 .Guest.r13 resq 1
134 .Guest.r14 resq 1
135 .Guest.r15 resq 1
136 .Guest.es.Sel resw 1
137 .Guest.es.PaddingSel resw 1
138 .Guest.es.ValidSel resw 1
139 .Guest.es.fFlags resw 1
140 .Guest.es.u64Base resq 1
141 .Guest.es.u32Limit resd 1
142 .Guest.es.Attr resd 1
143 .Guest.cs.Sel resw 1
144 .Guest.cs.PaddingSel resw 1
145 .Guest.cs.ValidSel resw 1
146 .Guest.cs.fFlags resw 1
147 .Guest.cs.u64Base resq 1
148 .Guest.cs.u32Limit resd 1
149 .Guest.cs.Attr resd 1
150 .Guest.ss.Sel resw 1
151 .Guest.ss.PaddingSel resw 1
152 .Guest.ss.ValidSel resw 1
153 .Guest.ss.fFlags resw 1
154 .Guest.ss.u64Base resq 1
155 .Guest.ss.u32Limit resd 1
156 .Guest.ss.Attr resd 1
157 .Guest.ds.Sel resw 1
158 .Guest.ds.PaddingSel resw 1
159 .Guest.ds.ValidSel resw 1
160 .Guest.ds.fFlags resw 1
161 .Guest.ds.u64Base resq 1
162 .Guest.ds.u32Limit resd 1
163 .Guest.ds.Attr resd 1
164 .Guest.fs.Sel resw 1
165 .Guest.fs.PaddingSel resw 1
166 .Guest.fs.ValidSel resw 1
167 .Guest.fs.fFlags resw 1
168 .Guest.fs.u64Base resq 1
169 .Guest.fs.u32Limit resd 1
170 .Guest.fs.Attr resd 1
171 .Guest.gs.Sel resw 1
172 .Guest.gs.PaddingSel resw 1
173 .Guest.gs.ValidSel resw 1
174 .Guest.gs.fFlags resw 1
175 .Guest.gs.u64Base resq 1
176 .Guest.gs.u32Limit resd 1
177 .Guest.gs.Attr resd 1
178 .Guest.ldtr.Sel resw 1
179 .Guest.ldtr.PaddingSel resw 1
180 .Guest.ldtr.ValidSel resw 1
181 .Guest.ldtr.fFlags resw 1
182 .Guest.ldtr.u64Base resq 1
183 .Guest.ldtr.u32Limit resd 1
184 .Guest.ldtr.Attr resd 1
185 .Guest.tr.Sel resw 1
186 .Guest.tr.PaddingSel resw 1
187 .Guest.tr.ValidSel resw 1
188 .Guest.tr.fFlags resw 1
189 .Guest.tr.u64Base resq 1
190 .Guest.tr.u32Limit resd 1
191 .Guest.tr.Attr resd 1
192 alignb 8
193 .Guest.eip resq 1
194 .Guest.eflags resq 1
195 .Guest.fExtrn resq 1
196 .Guest.uRipInhibitInt resq 1
197 .Guest.cr0 resq 1
198 .Guest.cr2 resq 1
199 .Guest.cr3 resq 1
200 .Guest.cr4 resq 1
201 .Guest.dr resq 8
202 .Guest.gdtrPadding resw 3
203 .Guest.gdtr resw 0
204 .Guest.gdtr.cbGdt resw 1
205 .Guest.gdtr.pGdt resq 1
206 .Guest.idtrPadding resw 3
207 .Guest.idtr resw 0
208 .Guest.idtr.cbIdt resw 1
209 .Guest.idtr.pIdt resq 1
210 .Guest.SysEnter.cs resb 8
211 .Guest.SysEnter.eip resb 8
212 .Guest.SysEnter.esp resb 8
213 .Guest.msrEFER resb 8
214 .Guest.msrSTAR resb 8
215 .Guest.msrPAT resb 8
216 .Guest.msrLSTAR resb 8
217 .Guest.msrCSTAR resb 8
218 .Guest.msrSFMASK resb 8
219 .Guest.msrKERNELGSBASE resb 8
220
221 alignb 32
222 .Guest.aPaePdpes resq 4
223
224 alignb 8
225 .Guest.aXcr resq 2
226 .Guest.fXStateMask resq 1
227 .Guest.fUsedFpuGuest resb 1
228 alignb 8
229 .Guest.aoffXState resw 64
230 alignb 256
231 .Guest.abXState resb 0x4000-0x300
232 .Guest.XState EQU .Guest.abXState
233
234;;
235 alignb 4096
236 .Guest.hwvirt resb 0
237 .Guest.hwvirt.svm resb 0
238 .Guest.hwvirt.vmx resb 0
239
240 .Guest.hwvirt.svm.Vmcb EQU .Guest.hwvirt.svm
241 .Guest.hwvirt.svm.abMsrBitmap EQU (.Guest.hwvirt.svm.Vmcb + 0x1000)
242 .Guest.hwvirt.svm.abIoBitmap EQU (.Guest.hwvirt.svm.abMsrBitmap + 0x2000)
243 .Guest.hwvirt.svm.uMsrHSavePa EQU (.Guest.hwvirt.svm.abIoBitmap + 0x3000) ; resq 1
244 .Guest.hwvirt.svm.GCPhysVmcb EQU (.Guest.hwvirt.svm.uMsrHSavePa + 8) ; resq 1
245 alignb 8
246 .Guest.hwvirt.svm.HostState EQU (.Guest.hwvirt.svm.GCPhysVmcb + 8) ; resb 184
247 .Guest.hwvirt.svm.uPrevPauseTick EQU (.Guest.hwvirt.svm.HostState + 184) ; resq 1
248 .Guest.hwvirt.svm.cPauseFilter EQU (.Guest.hwvirt.svm.uPrevPauseTick + 8) ; resw 1
249 .Guest.hwvirt.svm.cPauseFilterThreshold EQU (.Guest.hwvirt.svm.cPauseFilter + 2) ; resw 1
250 .Guest.hwvirt.svm.fInterceptEvents EQU (.Guest.hwvirt.svm.cPauseFilterThreshold + 2) ; resb 1
251
252 .Guest.hwvirt.vmx.Vmcs resb 0x1000
253 .Guest.hwvirt.vmx.ShadowVmcs resb 0x1000
254 .Guest.hwvirt.vmx.abVmreadBitmap resb 0x1000
255 .Guest.hwvirt.vmx.abVmwriteBitmap resb 0x1000
256 .Guest.hwvirt.vmx.aEntryMsrLoadArea resb 0x2000
257 .Guest.hwvirt.vmx.aExitMsrStoreArea resb 0x2000
258 .Guest.hwvirt.vmx.aExitMsrLoadArea resb 0x2000
259 .Guest.hwvirt.vmx.abMsrBitmap resb 0x1000
260 .Guest.hwvirt.vmx.abIoBitmap resb 0x1000+0x1000
261 alignb 8
262 .Guest.hwvirt.vmx.GCPhysVmxon resq 1
263 .Guest.hwvirt.vmx.GCPhysVmcs resq 1
264 .Guest.hwvirt.vmx.GCPhysShadowVmcs resq 1
265 .Guest.hwvirt.vmx.enmDiag resd 1
266 .Guest.hwvirt.vmx.enmAbort resd 1
267 .Guest.hwvirt.vmx.uDiagAux resq 1
268 .Guest.hwvirt.vmx.uAbortAux resd 1
269 .Guest.hwvirt.vmx.fInVmxRootMode resb 1
270 .Guest.hwvirt.vmx.fInVmxNonRootMode resb 1
271 .Guest.hwvirt.vmx.fInterceptEvents resb 1
272 .Guest.hwvirt.vmx.fNmiUnblockingIret resb 1
273 .Guest.hwvirt.vmx.uFirstPauseLoopTick resq 1
274 .Guest.hwvirt.vmx.uPrevPauseTick resq 1
275 .Guest.hwvirt.vmx.uEntryTick resq 1
276 .Guest.hwvirt.vmx.offVirtApicWrite resw 1
277 .Guest.hwvirt.vmx.fVirtNmiBlocking resb 1
278 alignb 8
279 .Guest.hwvirt.vmx.Msrs resb 224
280
281 alignb 8
282 .Guest.hwvirt.enmHwvirt resd 1
283 .Guest.hwvirt.fGif resb 1
284 alignb 4
285 .Guest.hwvirt.fSavedInhibit resd 1
286 alignb 64
287
288 .GuestMsrs resq 0
289 .GuestMsrs.au64 resq 64
290
291 ;
292 ; Other stuff.
293 ;
294 .hNestedVmxPreemptTimer resq 1
295
296 .fUseFlags resd 1
297 .fChanged resd 1
298 .u32RetCode resd 1
299 .fCpuIdApicFeatureVisible resb 1
300
301 ;
302 ; Host context state
303 ;
304 alignb 64
305 .Host resb 0
306 .Host.abXState resb 0x4000-0x300
307 .Host.XState EQU .Host.abXState
308 ;.Host.rax resq 1 - scratch
309 .Host.rbx resq 1
310 ;.Host.rcx resq 1 - scratch
311 ;.Host.rdx resq 1 - scratch
312 .Host.rdi resq 1
313 .Host.rsi resq 1
314 .Host.rbp resq 1
315 .Host.rsp resq 1
316 ;.Host.r8 resq 1 - scratch
317 ;.Host.r9 resq 1 - scratch
318 .Host.r10 resq 1
319 .Host.r11 resq 1
320 .Host.r12 resq 1
321 .Host.r13 resq 1
322 .Host.r14 resq 1
323 .Host.r15 resq 1
324 ;.Host.rip resd 1 - scratch
325 .Host.rflags resq 1
326 .Host.ss resw 1
327 .Host.ssPadding resw 1
328 .Host.gs resw 1
329 .Host.gsPadding resw 1
330 .Host.fs resw 1
331 .Host.fsPadding resw 1
332 .Host.es resw 1
333 .Host.esPadding resw 1
334 .Host.ds resw 1
335 .Host.dsPadding resw 1
336 .Host.cs resw 1
337 .Host.csPadding resw 1
338
339 .Host.cr0Fpu:
340 .Host.cr0 resq 1
341 ;.Host.cr2 resq 1 - scratch
342 .Host.cr3 resq 1
343 .Host.cr4 resq 1
344 .Host.cr8 resq 1
345
346 .Host.dr0 resq 1
347 .Host.dr1 resq 1
348 .Host.dr2 resq 1
349 .Host.dr3 resq 1
350 .Host.dr6 resq 1
351 .Host.dr7 resq 1
352
353 .Host.gdtr resb 10 ; GDT limit + linear address
354 .Host.gdtrPadding resw 1
355 .Host.idtr resb 10 ; IDT limit + linear address
356 .Host.idtrPadding resw 1
357 .Host.ldtr resw 1
358 .Host.ldtrPadding resw 1
359 .Host.tr resw 1
360 .Host.trPadding resw 1
361
362 .Host.SysEnter.cs resq 1
363 .Host.SysEnter.eip resq 1
364 .Host.SysEnter.esp resq 1
365 .Host.FSbase resq 1
366 .Host.GSbase resq 1
367 .Host.efer resq 1
368 alignb 8
369 .Host.xcr0 resq 1
370 .Host.fXStateMask resq 1
371
372 ;
373 ; Hypervisor Context.
374 ;
375 alignb 64
376 .Hyper resq 0
377 .Hyper.dr resq 8
378 .Hyper.cr3 resq 1
379 alignb 64
380
381%ifdef VBOX_WITH_CRASHDUMP_MAGIC
382 .aMagic resb 56
383 .uMagic resq 1
384%endif
385endstruc
386
387
388
389%if 0 ; Currently not used anywhere.
390;;
391; Macro for FXSAVE/FXRSTOR leaky behaviour on AMD CPUs, see cpumR3CheckLeakyFpu().
392;
393; Cleans the FPU state, if necessary, before restoring the FPU.
394;
395; This macro ASSUMES CR0.TS is not set!
396;
397; @param xDX Pointer to CPUMCPU.
398; @uses xAX, EFLAGS
399;
400; Changes here should also be reflected in CPUMRCA.asm's copy!
401;
402%macro CLEANFPU 0
403 test dword [xDX + CPUMCPU.fUseFlags], CPUM_USE_FFXSR_LEAKY
404 jz .nothing_to_clean
405
406 xor eax, eax
407 fnstsw ax ; FSW -> AX.
408 test eax, RT_BIT(7) ; If FSW.ES (bit 7) is set, clear it to not cause FPU exceptions
409 ; while clearing & loading the FPU bits in 'clean_fpu' below.
410 jz .clean_fpu
411 fnclex
412
413.clean_fpu:
414 ffree st7 ; Clear FPU stack register(7)'s tag entry to prevent overflow if a wraparound occurs.
415 ; for the upcoming push (load)
416 fild dword [g_r32_Zero xWrtRIP] ; Explicit FPU load to overwrite FIP, FOP, FDP registers in the FPU.
417.nothing_to_clean:
418%endmacro
419%endif ; Unused.
420
421
422;;
423; Makes sure we don't trap (#NM) accessing the FPU.
424;
425; In ring-0 this is a bit of work since we may have try convince the host kernel
426; to do the work for us, also, we must report any CR0 changes back to HMR0VMX
427; via the VINF_CPUM_HOST_CR0_MODIFIED status code.
428;
429; If we end up clearing CR0.TS/EM ourselves in ring-0, we'll save the original
430; value in CPUMCPU.Host.cr0Fpu. If we don't, we'll store zero there. (See also
431; CPUMRZ_RESTORE_CR0_IF_TS_OR_EM_SET.)
432;
433; In raw-mode we will always have to clear TS and it will be recalculated
434; elsewhere and thus needs no saving.
435;
436; @param %1 Register to return the return status code in.
437; @param %2 Temporary scratch register.
438; @param %3 Ring-0 only, register pointing to the CPUMCPU structure
439; of the EMT we're on.
440; @uses EFLAGS, CR0, %1, %2
441;
442%macro CPUMRZ_TOUCH_FPU_CLEAR_CR0_FPU_TRAPS_SET_RC 3
443 ;
444 ; ring-0 - slightly complicated (than old raw-mode).
445 ;
446 xor %1, %1 ; 0 / VINF_SUCCESS. Wishing for no CR0 changes.
447 mov [%3 + CPUMCPU.Host.cr0Fpu], %1
448
449 mov %2, cr0
450 test %2, X86_CR0_TS | X86_CR0_EM ; Make sure its safe to access the FPU state.
451 jz %%no_cr0_change
452
453 %ifdef VMM_R0_TOUCH_FPU
454 ; Touch the state and check that the kernel updated CR0 for us.
455 movdqa xmm0, xmm0
456 mov %2, cr0
457 test %2, X86_CR0_TS | X86_CR0_EM
458 jz %%cr0_changed
459 %endif
460
461 ; Save CR0 and clear them flags ourselves.
462 mov [%3 + CPUMCPU.Host.cr0Fpu], %2
463 and %2, ~(X86_CR0_TS | X86_CR0_EM)
464 mov cr0, %2
465
466%%cr0_changed:
467 mov %1, VINF_CPUM_HOST_CR0_MODIFIED
468%%no_cr0_change:
469%endmacro
470
471
472;;
473; Restore CR0 if CR0.TS or CR0.EM were non-zero in the original state.
474;
475; @param %1 The original state to restore (or zero).
476;
477%macro CPUMRZ_RESTORE_CR0_IF_TS_OR_EM_SET 1
478 test %1, X86_CR0_TS | X86_CR0_EM
479 jz %%skip_cr0_restore
480 mov cr0, %1
481%%skip_cr0_restore:
482%endmacro
483
484
485;;
486; Saves the host state.
487;
488; @uses rax, rdx
489; @param pCpumCpu Define for the register containing the CPUMCPU pointer.
490; @param pXState Define for the register containing the extended state pointer.
491;
492%macro CPUMR0_SAVE_HOST 0
493 ;
494 ; Load a couple of registers we'll use later in all branches.
495 ;
496 lea pXState, [pCpumCpu + CPUMCPU.Host.XState]
497 mov eax, [pCpumCpu + CPUMCPU.Host.fXStateMask]
498
499 ;
500 ; XSAVE or FXSAVE?
501 ;
502 or eax, eax
503 jz %%host_fxsave
504
505 ; XSAVE
506 mov edx, [pCpumCpu + CPUMCPU.Host.fXStateMask + 4]
507 %ifdef RT_ARCH_AMD64
508 o64 xsave [pXState]
509 %else
510 xsave [pXState]
511 %endif
512 jmp %%host_done
513
514 ; FXSAVE
515%%host_fxsave:
516 %ifdef RT_ARCH_AMD64
517 o64 fxsave [pXState] ; Use explicit REX prefix. See @bugref{6398}.
518 %else
519 fxsave [pXState]
520 %endif
521
522%%host_done:
523%endmacro ; CPUMR0_SAVE_HOST
524
525
526;;
527; Loads the host state.
528;
529; @uses rax, rdx
530; @param pCpumCpu Define for the register containing the CPUMCPU pointer.
531; @param pXState Define for the register containing the extended state pointer.
532;
533%macro CPUMR0_LOAD_HOST 0
534 ;
535 ; Load a couple of registers we'll use later in all branches.
536 ;
537 lea pXState, [pCpumCpu + CPUMCPU.Host.XState]
538 mov eax, [pCpumCpu + CPUMCPU.Host.fXStateMask]
539
540 ;
541 ; XRSTOR or FXRSTOR?
542 ;
543 or eax, eax
544 jz %%host_fxrstor
545
546 ; XRSTOR
547 mov edx, [pCpumCpu + CPUMCPU.Host.fXStateMask + 4]
548 %ifdef RT_ARCH_AMD64
549 o64 xrstor [pXState]
550 %else
551 xrstor [pXState]
552 %endif
553 jmp %%host_done
554
555 ; FXRSTOR
556%%host_fxrstor:
557 %ifdef RT_ARCH_AMD64
558 o64 fxrstor [pXState] ; Use explicit REX prefix. See @bugref{6398}.
559 %else
560 fxrstor [pXState]
561 %endif
562
563%%host_done:
564%endmacro ; CPUMR0_LOAD_HOST
565
566
567
568;; Macro for XSAVE/FXSAVE for the guest FPU but tries to figure out whether to
569; save the 32-bit FPU state or 64-bit FPU state.
570;
571; @param %1 Pointer to CPUMCPU.
572; @param %2 Pointer to XState.
573; @param %3 Force AMD64
574; @param %4 The instruction to use (xsave or fxsave)
575; @uses xAX, xDX, EFLAGS, 20h of stack.
576;
577%macro SAVE_32_OR_64_FPU 4
578%if CPUM_IS_AMD64 || %3
579 ; Save the guest FPU (32-bit or 64-bit), preserves existing broken state. See @bugref{7138}.
580 test dword [pCpumCpu + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
581 jnz short %%save_long_mode_guest
582%endif
583 %4 [pXState]
584%if CPUM_IS_AMD64 || %3
585 jmp %%save_done_32bit_cs_ds
586
587%%save_long_mode_guest:
588 o64 %4 [pXState]
589
590 xor edx, edx
591 cmp dword [pXState + X86FXSTATE.FPUCS], 0
592 jne short %%save_done
593
594 sub rsp, 20h ; Only need 1ch bytes but keep stack aligned otherwise we #GP(0).
595 fnstenv [rsp]
596 movzx eax, word [rsp + 10h]
597 mov [pXState + X86FXSTATE.FPUCS], eax
598 movzx eax, word [rsp + 18h]
599 add rsp, 20h
600 mov [pXState + X86FXSTATE.FPUDS], eax
601%endif
602%%save_done_32bit_cs_ds:
603 mov edx, X86_FXSTATE_RSVD_32BIT_MAGIC
604%%save_done:
605 mov dword [pXState + X86_OFF_FXSTATE_RSVD], edx
606%endmacro ; SAVE_32_OR_64_FPU
607
608
609;;
610; Save the guest state.
611;
612; @uses rax, rdx
613; @param pCpumCpu Define for the register containing the CPUMCPU pointer.
614; @param pXState Define for the register containing the extended state pointer.
615;
616%macro CPUMR0_SAVE_GUEST 0
617 ;
618 ; Load a couple of registers we'll use later in all branches.
619 ;
620 %ifdef IN_RING0
621 lea pXState, [pCpumCpu + CPUMCPU.Guest.XState]
622 %else
623 %error "Unsupported context!"
624 %endif
625 mov eax, [pCpumCpu + CPUMCPU.Guest.fXStateMask]
626
627 ;
628 ; XSAVE or FXSAVE?
629 ;
630 or eax, eax
631 jz %%guest_fxsave
632
633 ; XSAVE
634 mov edx, [pCpumCpu + CPUMCPU.Guest.fXStateMask + 4]
635 %ifdef VBOX_WITH_KERNEL_USING_XMM
636 and eax, ~CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS ; Already saved in HMR0A.asm.
637 %endif
638 SAVE_32_OR_64_FPU pCpumCpu, pXState, 0, xsave
639 jmp %%guest_done
640
641 ; FXSAVE
642%%guest_fxsave:
643 SAVE_32_OR_64_FPU pCpumCpu, pXState, 0, fxsave
644
645%%guest_done:
646%endmacro ; CPUMR0_SAVE_GUEST
647
648
649;;
650; Wrapper for selecting 32-bit or 64-bit XRSTOR/FXRSTOR according to what SAVE_32_OR_64_FPU did.
651;
652; @param %1 Pointer to CPUMCPU.
653; @param %2 Pointer to XState.
654; @param %3 Force AMD64.
655; @param %4 The instruction to use (xrstor or fxrstor).
656; @uses xAX, xDX, EFLAGS
657;
658%macro RESTORE_32_OR_64_FPU 4
659%if CPUM_IS_AMD64 || %3
660 ; Restore the guest FPU (32-bit or 64-bit), preserves existing broken state. See @bugref{7138}.
661 test dword [pCpumCpu + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
662 jz %%restore_32bit_fpu
663 cmp dword [pXState + X86_OFF_FXSTATE_RSVD], X86_FXSTATE_RSVD_32BIT_MAGIC
664 jne short %%restore_64bit_fpu
665%%restore_32bit_fpu:
666%endif
667 %4 [pXState]
668%if CPUM_IS_AMD64 || %3
669 ; TODO: Restore XMM8-XMM15!
670 jmp short %%restore_fpu_done
671%%restore_64bit_fpu:
672 o64 %4 [pXState]
673%%restore_fpu_done:
674%endif
675%endmacro ; RESTORE_32_OR_64_FPU
676
677
678;;
679; Loads the guest state.
680;
681; @uses rax, rdx
682; @param pCpumCpu Define for the register containing the CPUMCPU pointer.
683; @param pXState Define for the register containing the extended state pointer.
684;
685%macro CPUMR0_LOAD_GUEST 0
686 ;
687 ; Load a couple of registers we'll use later in all branches.
688 ;
689 lea pXState, [pCpumCpu + CPUMCPU.Guest.XState]
690 mov eax, [pCpumCpu + CPUMCPU.Guest.fXStateMask]
691
692 ;
693 ; XRSTOR or FXRSTOR?
694 ;
695 or eax, eax
696 jz %%guest_fxrstor
697
698 ; XRSTOR
699 mov edx, [pCpumCpu + CPUMCPU.Guest.fXStateMask + 4]
700 %ifdef VBOX_WITH_KERNEL_USING_XMM
701 and eax, ~CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS ; Will be loaded by HMR0A.asm.
702 %endif
703 RESTORE_32_OR_64_FPU pCpumCpu, pXState, 0, xrstor
704 jmp %%guest_done
705
706 ; FXRSTOR
707%%guest_fxrstor:
708 RESTORE_32_OR_64_FPU pCpumCpu, pXState, 0, fxrstor
709
710%%guest_done:
711%endmacro ; CPUMR0_LOAD_GUEST
712
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