VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/CPUMR0A.asm@ 53349

Last change on this file since 53349 was 52465, checked in by vboxsync, 10 years ago

VMM: Fix IEM FXSAVE implementation to match the logic in HM/raw-mode FPU handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1; $Id: CPUMR0A.asm 52465 2014-08-22 11:39:08Z vboxsync $
2;; @file
3; CPUM - Guest Context Assembly Routines.
4;
5
6;
7; Copyright (C) 2006-2013 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/vmm/vm.mac"
23%include "VBox/err.mac"
24%include "VBox/vmm/stam.mac"
25%include "CPUMInternal.mac"
26%include "iprt/x86.mac"
27%include "VBox/vmm/cpum.mac"
28
29%ifdef IN_RING3
30 %error "The jump table doesn't link on leopard."
31%endif
32
33;*******************************************************************************
34;* Defined Constants And Macros *
35;*******************************************************************************
36;; The offset of the XMM registers in X86FXSTATE.
37; Use define because I'm too lazy to convert the struct.
38%define XMM_OFF_IN_X86FXSTATE 160
39%define IP_OFF_IN_X86FXSTATE 08h
40%define CS_OFF_IN_X86FXSTATE 0ch
41%define DS_OFF_IN_X86FXSTATE 14h
42
43
44;*******************************************************************************
45;* External Symbols *
46;*******************************************************************************
47%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
48extern NAME(SUPR0AbsIs64bit)
49extern NAME(SUPR0Abs64bitKernelCS)
50extern NAME(SUPR0Abs64bitKernelSS)
51extern NAME(SUPR0Abs64bitKernelDS)
52extern NAME(SUPR0AbsKernelCS)
53%endif
54
55
56;*******************************************************************************
57;* Global Variables *
58;*******************************************************************************
59%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
60BEGINDATA
61;;
62; Store the SUPR0AbsIs64bit absolute value here so we can cmp/test without
63; needing to clobber a register. (This trick doesn't quite work for PE btw.
64; but that's not relevant atm.)
65GLOBALNAME g_fCPUMIs64bitHost
66 dd NAME(SUPR0AbsIs64bit)
67%endif
68
69
70BEGINCODE
71
72;; Macro for FXSAVE/FXRSTOR leaky behaviour on AMD CPUs, see cpumR3CheckLeakyFpu().
73; Cleans the FPU state, if necessary, before restoring the FPU.
74;
75; This macro ASSUMES CR0.TS is not set!
76; @remarks Trashes xAX!!
77; Changes here should also be reflected in CPUMRCA.asm's copy!
78%macro CLEANFPU 0
79 test dword [xDX + CPUMCPU.fUseFlags], CPUM_USE_FFXSR_LEAKY
80 jz .nothing_to_clean
81
82 xor eax, eax
83 fnstsw ax ; Get FSW
84 test eax, RT_BIT(7) ; If FSW.ES (bit 7) is set, clear it to not cause FPU exceptions
85 ; while clearing & loading the FPU bits in 'clean_fpu'
86 jz .clean_fpu
87 fnclex
88
89.clean_fpu:
90 ffree st7 ; Clear FPU stack register(7)'s tag entry to prevent overflow if a wraparound occurs
91 ; for the upcoming push (load)
92 fild dword [xDX + CPUMCPU.Guest.fpu] ; Explicit FPU load to overwrite FIP, FOP, FDP registers in the FPU.
93
94.nothing_to_clean:
95%endmacro
96
97
98;; Macro for FXSAVE for the guest FPU but tries to figure out whether to
99; save the 32-bit FPU state or 64-bit FPU state.
100;
101; @remarks Requires CPUMCPU pointer in RDX
102%macro SAVE_32_OR_64_FPU 0
103 o64 fxsave [rdx + CPUMCPU.Guest.fpu]
104
105 ; Shouldn't be necessary to check if the entire 64-bit FIP is 0 (i.e. guest hasn't used its FPU yet) because it should
106 ; be taken care of by the calling code, i.e. hmR0[Vmx|Svm]LoadSharedCR0() and hmR0[Vmx|Svm]ExitXcptNm() which ensure
107 ; we swap the guest FPU state when it starts using it (#NM). In any case it's only a performance optimization.
108 ; cmp qword [rdx + CPUMCPU.Guest.fpu + IP_OFF_IN_X86FXSTATE], 0
109 ; je short %%save_done
110
111 cmp dword [rdx + CPUMCPU.Guest.fpu + CS_OFF_IN_X86FXSTATE], 0
112 jne short %%save_done
113 sub rsp, 20h ; Only need 1ch bytes but keep stack aligned otherwise we #GP(0)
114 fnstenv [rsp]
115 movzx eax, word [rsp + 10h]
116 mov [rdx + CPUMCPU.Guest.fpu + CS_OFF_IN_X86FXSTATE], eax
117 movzx eax, word [rsp + 18h]
118 mov [rdx + CPUMCPU.Guest.fpu + DS_OFF_IN_X86FXSTATE], eax
119 add rsp, 20h
120 mov dword [rdx + CPUMCPU.Guest.fpu + X86_OFF_FXSTATE_RSVD], X86_FXSTATE_RSVD_32BIT_MAGIC
121%%save_done:
122%endmacro
123
124;; Macro for FXRSTOR for the guest FPU but loads the one based on what
125; was saved before using SAVE_32_OR_64_FPU().
126;
127; @remarks Requires CPUMCPU pointer in RDX
128%macro RESTORE_32_OR_64_FPU 0
129 cmp dword [rdx + CPUMCPU.Guest.fpu + X86_OFF_FXSTATE_RSVD], X86_FXSTATE_RSVD_32BIT_MAGIC
130 jne short %%restore_64bit_fpu
131 fxrstor [rdx + CPUMCPU.Guest.fpu]
132 jmp short %%restore_fpu_done
133%%restore_64bit_fpu:
134 o64 fxrstor [rdx + CPUMCPU.Guest.fpu]
135%%restore_fpu_done:
136%endmacro
137
138
139;; Macro to save and modify CR0 (if necessary) before touching the FPU state
140; so as to not cause any FPU exceptions.
141;
142; @remarks Uses xCX for backing-up CR0 (if CR0 needs to be modified) otherwise clears xCX.
143; @remarks Trashes xAX.
144%macro SAVE_CR0_CLEAR_FPU_TRAPS 0
145 xor ecx, ecx
146 mov xAX, cr0
147 test eax, X86_CR0_TS | X86_CR0_EM ; Make sure its safe to access the FPU state.
148 jz %%skip_cr0_write
149 mov xCX, xAX ; Save old CR0
150 and xAX, ~(X86_CR0_TS | X86_CR0_EM)
151 mov cr0, xAX
152%%skip_cr0_write:
153%endmacro
154
155;; Macro to restore CR0 from xCX if necessary.
156;
157; @remarks xCX should contain the CR0 value to restore or 0 if no restoration is needed.
158%macro RESTORE_CR0 0
159 cmp ecx, 0
160 je %%skip_cr0_restore
161 mov cr0, xCX
162%%skip_cr0_restore:
163%endmacro
164
165
166;;
167; Saves the host FPU/XMM state and restores the guest state.
168;
169; @returns 0
170; @param pCPUMCPU x86:[esp+4] gcc:rdi msc:rcx CPUMCPU pointer
171;
172align 16
173BEGINPROC cpumR0SaveHostRestoreGuestFPUState
174%ifdef RT_ARCH_AMD64
175 %ifdef RT_OS_WINDOWS
176 mov xDX, rcx
177 %else
178 mov xDX, rdi
179 %endif
180%else
181 mov xDX, dword [esp + 4]
182%endif
183 pushf ; The darwin kernel can get upset or upset things if an
184 cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
185
186 ; Switch the state.
187 or dword [xDX + CPUMCPU.fUseFlags], (CPUM_USED_FPU | CPUM_USED_FPU_SINCE_REM)
188
189 ; Clear CR0 FPU bits to not cause exceptions, uses xCX
190 SAVE_CR0_CLEAR_FPU_TRAPS
191 ; Do NOT use xCX from this point!
192
193%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
194 cmp byte [NAME(g_fCPUMIs64bitHost)], 0
195 jz .legacy_mode
196 db 0xea ; jmp far .sixtyfourbit_mode
197 dd .sixtyfourbit_mode, NAME(SUPR0Abs64bitKernelCS)
198.legacy_mode:
199%endif ; VBOX_WITH_HYBRID_32BIT_KERNEL
200
201%ifdef RT_ARCH_AMD64
202 ; Use explicit REX prefix. See @bugref{6398}.
203 o64 fxsave [rdx + CPUMCPU.Host.fpu] ; ASSUMES that all VT-x/AMD-V boxes sports fxsave/fxrstor (safe assumption)
204
205 ; Restore the guest FPU (32-bit or 64-bit), preserves existing broken state. See @bugref{7138}.
206 test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
207 jnz short .fpu_load_32_or_64
208 fxrstor [rdx + CPUMCPU.Guest.fpu]
209 jmp short .fpu_load_done
210.fpu_load_32_or_64:
211 RESTORE_32_OR_64_FPU
212.fpu_load_done:
213%else
214 fxsave [edx + CPUMCPU.Host.fpu] ; ASSUMES that all VT-x/AMD-V boxes sports fxsave/fxrstor (safe assumption)
215 fxrstor [edx + CPUMCPU.Guest.fpu]
216%endif
217
218%ifdef VBOX_WITH_KERNEL_USING_XMM
219 ; Restore the non-volatile xmm registers. ASSUMING 64-bit windows
220 lea r11, [xDX + CPUMCPU.Host.fpu + XMM_OFF_IN_X86FXSTATE]
221 movdqa xmm6, [r11 + 060h]
222 movdqa xmm7, [r11 + 070h]
223 movdqa xmm8, [r11 + 080h]
224 movdqa xmm9, [r11 + 090h]
225 movdqa xmm10, [r11 + 0a0h]
226 movdqa xmm11, [r11 + 0b0h]
227 movdqa xmm12, [r11 + 0c0h]
228 movdqa xmm13, [r11 + 0d0h]
229 movdqa xmm14, [r11 + 0e0h]
230 movdqa xmm15, [r11 + 0f0h]
231%endif
232
233.done:
234 ; Restore CR0 from xCX if it was previously saved.
235 RESTORE_CR0
236 popf
237 xor eax, eax
238 ret
239
240%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
241ALIGNCODE(16)
242BITS 64
243.sixtyfourbit_mode:
244 and edx, 0ffffffffh
245 o64 fxsave [rdx + CPUMCPU.Host.fpu]
246
247 ; Restore the guest FPU (32-bit or 64-bit), preserves existing broken state. See @bugref{7138}.
248 test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
249 jnz short .fpu_load_32_or_64_darwin
250 fxrstor [rdx + CPUMCPU.Guest.fpu]
251 jmp short .fpu_load_done_darwin
252.fpu_load_32_or_64_darwin:
253 RESTORE_32_OR_64_FPU
254.fpu_load_done_darwin:
255
256 jmp far [.fpret wrt rip]
257.fpret: ; 16:32 Pointer to .the_end.
258 dd .done, NAME(SUPR0AbsKernelCS)
259BITS 32
260%endif
261ENDPROC cpumR0SaveHostRestoreGuestFPUState
262
263
264%ifndef RT_ARCH_AMD64
265%ifdef VBOX_WITH_64_BITS_GUESTS
266%ifndef VBOX_WITH_HYBRID_32BIT_KERNEL
267;;
268; Saves the host FPU/XMM state
269;
270; @returns 0
271; @param pCPUMCPU x86:[esp+4] gcc:rdi msc:rcx CPUMCPU pointer
272;
273align 16
274BEGINPROC cpumR0SaveHostFPUState
275 mov xDX, dword [esp + 4]
276 pushf ; The darwin kernel can get upset or upset things if an
277 cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
278
279 ; Switch the state.
280 or dword [xDX + CPUMCPU.fUseFlags], (CPUM_USED_FPU | CPUM_USED_FPU_SINCE_REM)
281
282 ; Clear CR0 FPU bits to not cause exceptions, uses xCX
283 SAVE_CR0_CLEAR_FPU_TRAPS
284 ; Do NOT use xCX from this point!
285
286 fxsave [xDX + CPUMCPU.Host.fpu] ; ASSUMES that all VT-x/AMD-V boxes support fxsave/fxrstor (safe assumption)
287
288 ; Restore CR0 from xCX if it was saved previously.
289 RESTORE_CR0
290
291 popf
292 xor eax, eax
293 ret
294ENDPROC cpumR0SaveHostFPUState
295%endif
296%endif
297%endif
298
299
300;;
301; Saves the guest FPU/XMM state and restores the host state.
302;
303; @returns 0
304; @param pCPUMCPU x86:[esp+4] gcc:rdi msc:rcx CPUMCPU pointer
305;
306align 16
307BEGINPROC cpumR0SaveGuestRestoreHostFPUState
308%ifdef RT_ARCH_AMD64
309 %ifdef RT_OS_WINDOWS
310 mov xDX, rcx
311 %else
312 mov xDX, rdi
313 %endif
314%else
315 mov xDX, dword [esp + 4]
316%endif
317
318 ; Only restore FPU if guest has used it.
319 ; Using fxrstor should ensure that we're not causing unwanted exception on the host.
320 test dword [xDX + CPUMCPU.fUseFlags], CPUM_USED_FPU
321 jz .fpu_not_used
322
323 pushf ; The darwin kernel can get upset or upset things if an
324 cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
325
326 ; Clear CR0 FPU bits to not cause exceptions, uses xCX
327 SAVE_CR0_CLEAR_FPU_TRAPS
328 ; Do NOT use xCX from this point!
329
330%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
331 cmp byte [NAME(g_fCPUMIs64bitHost)], 0
332 jz .legacy_mode
333 db 0xea ; jmp far .sixtyfourbit_mode
334 dd .sixtyfourbit_mode, NAME(SUPR0Abs64bitKernelCS)
335.legacy_mode:
336%endif ; VBOX_WITH_HYBRID_32BIT_KERNEL
337
338%ifdef RT_ARCH_AMD64
339 ; Save the guest FPU (32-bit or 64-bit), preserves existing broken state. See @bugref{7138}.
340 test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
341 jnz short .fpu_save_32_or_64
342 fxsave [rdx + CPUMCPU.Guest.fpu]
343 jmp short .fpu_save_done
344.fpu_save_32_or_64:
345 SAVE_32_OR_64_FPU
346.fpu_save_done:
347
348 ; Use explicit REX prefix. See @bugref{6398}.
349 o64 fxrstor [rdx + CPUMCPU.Host.fpu]
350%else
351 fxsave [edx + CPUMCPU.Guest.fpu] ; ASSUMES that all VT-x/AMD-V boxes support fxsave/fxrstor (safe assumption)
352 fxrstor [edx + CPUMCPU.Host.fpu]
353%endif
354
355.done:
356 ; Restore CR0 from xCX if it was previously saved.
357 RESTORE_CR0
358 and dword [xDX + CPUMCPU.fUseFlags], ~CPUM_USED_FPU
359 popf
360.fpu_not_used:
361 xor eax, eax
362 ret
363
364%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
365ALIGNCODE(16)
366BITS 64
367.sixtyfourbit_mode:
368 and edx, 0ffffffffh
369
370 ; Save the guest FPU (32-bit or 64-bit), preserves existing broken state. See @bugref{7138}.
371 test dword [rdx + CPUMCPU.fUseFlags], CPUM_USE_SUPPORTS_LONGMODE
372 jnz short .fpu_save_32_or_64_darwin
373 fxsave [rdx + CPUMCPU.Guest.fpu]
374 jmp short .fpu_save_done_darwin
375.fpu_save_32_or_64_darwin:
376 SAVE_32_OR_64_FPU
377.fpu_save_done_darwin:
378
379 o64 fxrstor [rdx + CPUMCPU.Host.fpu]
380 jmp far [.fpret wrt rip]
381.fpret: ; 16:32 Pointer to .the_end.
382 dd .done, NAME(SUPR0AbsKernelCS)
383BITS 32
384%endif
385ENDPROC cpumR0SaveGuestRestoreHostFPUState
386
387
388;;
389; Sets the host's FPU/XMM state
390;
391; @returns 0
392; @param pCPUMCPU x86:[esp+4] gcc:rdi msc:rcx CPUMCPU pointer
393;
394align 16
395BEGINPROC cpumR0RestoreHostFPUState
396%ifdef RT_ARCH_AMD64
397 %ifdef RT_OS_WINDOWS
398 mov xDX, rcx
399 %else
400 mov xDX, rdi
401 %endif
402%else
403 mov xDX, dword [esp + 4]
404%endif
405
406 ; Restore FPU if guest has used it.
407 ; Using fxrstor should ensure that we're not causing unwanted exception on the host.
408 test dword [xDX + CPUMCPU.fUseFlags], CPUM_USED_FPU
409 jz short .fpu_not_used
410
411 pushf ; The darwin kernel can get upset or upset things if an
412 cli ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
413
414 ; Clear CR0 FPU bits to not cause exceptions, uses xCX
415 SAVE_CR0_CLEAR_FPU_TRAPS
416 ; Do NOT use xCX from this point!
417
418%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
419 cmp byte [NAME(g_fCPUMIs64bitHost)], 0
420 jz .legacy_mode
421 db 0xea ; jmp far .sixtyfourbit_mode
422 dd .sixtyfourbit_mode, NAME(SUPR0Abs64bitKernelCS)
423.legacy_mode:
424%endif ; VBOX_WITH_HYBRID_32BIT_KERNEL
425
426%ifdef RT_ARCH_AMD64
427 o64 fxrstor [xDX + CPUMCPU.Host.fpu]
428%else
429 fxrstor [xDX + CPUMCPU.Host.fpu]
430%endif
431
432.done:
433 ; Restore CR0 from xCX if it was previously saved.
434 RESTORE_CR0
435 and dword [xDX + CPUMCPU.fUseFlags], ~CPUM_USED_FPU
436 popf
437.fpu_not_used:
438 xor eax, eax
439 ret
440
441%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
442ALIGNCODE(16)
443BITS 64
444.sixtyfourbit_mode:
445 and edx, 0ffffffffh
446 o64 fxrstor [rdx + CPUMCPU.Host.fpu]
447 jmp far [.fpret wrt rip]
448.fpret: ; 16:32 Pointer to .the_end.
449 dd .done, NAME(SUPR0AbsKernelCS)
450BITS 32
451%endif
452ENDPROC cpumR0RestoreHostFPUState
453
454
455%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
456;;
457; DECLASM(void) cpumR0SaveDRx(uint64_t *pa4Regs);
458;
459ALIGNCODE(16)
460BEGINPROC cpumR0SaveDRx
461%ifdef RT_ARCH_AMD64
462 %ifdef ASM_CALL64_GCC
463 mov xCX, rdi
464 %endif
465%else
466 mov xCX, dword [esp + 4]
467%endif
468 pushf ; Just to be on the safe side.
469 cli
470%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
471 cmp byte [NAME(g_fCPUMIs64bitHost)], 0
472 jz .legacy_mode
473 db 0xea ; jmp far .sixtyfourbit_mode
474 dd .sixtyfourbit_mode, NAME(SUPR0Abs64bitKernelCS)
475.legacy_mode:
476%endif ; VBOX_WITH_HYBRID_32BIT_KERNEL
477
478 ;
479 ; Do the job.
480 ;
481 mov xAX, dr0
482 mov xDX, dr1
483 mov [xCX], xAX
484 mov [xCX + 8 * 1], xDX
485 mov xAX, dr2
486 mov xDX, dr3
487 mov [xCX + 8 * 2], xAX
488 mov [xCX + 8 * 3], xDX
489
490.done:
491 popf
492 ret
493
494%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
495ALIGNCODE(16)
496BITS 64
497.sixtyfourbit_mode:
498 and ecx, 0ffffffffh
499
500 mov rax, dr0
501 mov rdx, dr1
502 mov r8, dr2
503 mov r9, dr3
504 mov [rcx], rax
505 mov [rcx + 8 * 1], rdx
506 mov [rcx + 8 * 2], r8
507 mov [rcx + 8 * 3], r9
508 jmp far [.fpret wrt rip]
509.fpret: ; 16:32 Pointer to .the_end.
510 dd .done, NAME(SUPR0AbsKernelCS)
511BITS 32
512%endif
513ENDPROC cpumR0SaveDRx
514
515
516;;
517; DECLASM(void) cpumR0LoadDRx(uint64_t const *pa4Regs);
518;
519ALIGNCODE(16)
520BEGINPROC cpumR0LoadDRx
521%ifdef RT_ARCH_AMD64
522 %ifdef ASM_CALL64_GCC
523 mov xCX, rdi
524 %endif
525%else
526 mov xCX, dword [esp + 4]
527%endif
528 pushf ; Just to be on the safe side.
529 cli
530%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
531 cmp byte [NAME(g_fCPUMIs64bitHost)], 0
532 jz .legacy_mode
533 db 0xea ; jmp far .sixtyfourbit_mode
534 dd .sixtyfourbit_mode, NAME(SUPR0Abs64bitKernelCS)
535.legacy_mode:
536%endif ; VBOX_WITH_HYBRID_32BIT_KERNEL
537
538 ;
539 ; Do the job.
540 ;
541 mov xAX, [xCX]
542 mov xDX, [xCX + 8 * 1]
543 mov dr0, xAX
544 mov dr1, xDX
545 mov xAX, [xCX + 8 * 2]
546 mov xDX, [xCX + 8 * 3]
547 mov dr2, xAX
548 mov dr3, xDX
549
550.done:
551 popf
552 ret
553
554%ifdef VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
555ALIGNCODE(16)
556BITS 64
557.sixtyfourbit_mode:
558 and ecx, 0ffffffffh
559
560 mov rax, [rcx]
561 mov rdx, [rcx + 8 * 1]
562 mov r8, [rcx + 8 * 2]
563 mov r9, [rcx + 8 * 3]
564 mov dr0, rax
565 mov dr1, rdx
566 mov dr2, r8
567 mov dr3, r9
568 jmp far [.fpret wrt rip]
569.fpret: ; 16:32 Pointer to .the_end.
570 dd .done, NAME(SUPR0AbsKernelCS)
571BITS 32
572%endif
573ENDPROC cpumR0LoadDRx
574
575%endif ; VBOX_WITH_HYBRID_32BIT_KERNEL_IN_R0
576
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