VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/CPUMRCA.asm@ 78285

Last change on this file since 78285 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.5 KB
Line 
1; $Id: CPUMRCA.asm 76553 2019-01-01 01:45:53Z vboxsync $
2;; @file
3; CPUM - Raw-mode Context Assembly Routines.
4;
5
6;
7; Copyright (C) 2006-2019 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 "VMMRC.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
30;*******************************************************************************
31;* External Symbols *
32;*******************************************************************************
33extern IMPNAME(g_CPUM) ; VMM GC Builtin import
34extern IMPNAME(g_VM) ; VMM GC Builtin import
35extern NAME(cpumRCHandleNPAndGP) ; CPUMGC.cpp
36extern NAME(CPUMRCAssertPreExecutionSanity)
37
38
39;
40; Enables write protection of Hypervisor memory pages.
41; !note! Must be commented out for Trap8 debug handler.
42;
43%define ENABLE_WRITE_PROTECTION 1
44
45BEGINCODE
46
47
48;;
49; Handles lazy FPU saving and restoring.
50;
51; This handler will implement lazy fpu (sse/mmx/stuff) saving.
52; Two actions may be taken in this handler since the Guest OS may
53; be doing lazy fpu switching. So, we'll have to generate those
54; traps which the Guest CPU CTX shall have according to the
55; its CR0 flags. If no traps for the Guest OS, we'll save the host
56; context and restore the guest context.
57;
58; @returns 0 if caller should continue execution.
59; @returns VINF_EM_RAW_GUEST_TRAP if a guest trap should be generated.
60; @param pCpumCpu [ebp+8] Pointer to the CPUMCPU.
61;
62align 16
63BEGINPROC cpumHandleLazyFPUAsm
64 push ebp
65 mov ebp, esp
66 push ebx
67 push esi
68 mov ebx, [ebp + 8]
69%define pCpumCpu ebx
70%define pXState esi
71
72 ;
73 ; Figure out what to do.
74 ;
75 ; There are two basic actions:
76 ; 1. Save host fpu and restore guest fpu.
77 ; 2. Generate guest trap.
78 ;
79 ; When entering the hypervisor we'll always enable MP (for proper wait
80 ; trapping) and TS (for intercepting all fpu/mmx/sse stuff). The EM flag
81 ; is taken from the guest OS in order to get proper SSE handling.
82 ;
83 ;
84 ; Actions taken depending on the guest CR0 flags:
85 ;
86 ; 3 2 1
87 ; TS | EM | MP | FPUInstr | WAIT :: VMM Action
88 ; ------------------------------------------------------------------------
89 ; 0 | 0 | 0 | Exec | Exec :: Clear TS & MP, Save HC, Load GC.
90 ; 0 | 0 | 1 | Exec | Exec :: Clear TS, Save HC, Load GC.
91 ; 0 | 1 | 0 | #NM | Exec :: Clear TS & MP, Save HC, Load GC;
92 ; 0 | 1 | 1 | #NM | Exec :: Clear TS, Save HC, Load GC.
93 ; 1 | 0 | 0 | #NM | Exec :: Clear MP, Save HC, Load GC. (EM is already cleared.)
94 ; 1 | 0 | 1 | #NM | #NM :: Go to host taking trap there.
95 ; 1 | 1 | 0 | #NM | Exec :: Clear MP, Save HC, Load GC. (EM is already set.)
96 ; 1 | 1 | 1 | #NM | #NM :: Go to host taking trap there.
97
98 ;
99 ; Before taking any of these actions we're checking if we have already
100 ; loaded the GC FPU. Because if we have, this is an trap for the guest - raw ring-3.
101 ;
102 test dword [pCpumCpu + CPUMCPU.fUseFlags], CPUM_USED_FPU_GUEST
103 jz hlfpua_not_loaded
104 jmp hlfpua_guest_trap
105
106 ;
107 ; Take action.
108 ;
109align 16
110hlfpua_not_loaded:
111 mov eax, [pCpumCpu + CPUMCPU.Guest.cr0]
112 and eax, X86_CR0_MP | X86_CR0_EM | X86_CR0_TS
113 jmp dword [eax*2 + hlfpuajmp1]
114align 16
115;; jump table using fpu related cr0 flags as index.
116hlfpuajmp1:
117 RTCCPTR_DEF hlfpua_switch_fpu_ctx
118 RTCCPTR_DEF hlfpua_switch_fpu_ctx
119 RTCCPTR_DEF hlfpua_switch_fpu_ctx
120 RTCCPTR_DEF hlfpua_switch_fpu_ctx
121 RTCCPTR_DEF hlfpua_switch_fpu_ctx
122 RTCCPTR_DEF hlfpua_guest_trap
123 RTCCPTR_DEF hlfpua_switch_fpu_ctx
124 RTCCPTR_DEF hlfpua_guest_trap
125;; and mask for cr0.
126hlfpu_afFlags:
127 RTCCPTR_DEF ~(X86_CR0_TS | X86_CR0_MP)
128 RTCCPTR_DEF ~(X86_CR0_TS)
129 RTCCPTR_DEF ~(X86_CR0_TS | X86_CR0_MP)
130 RTCCPTR_DEF ~(X86_CR0_TS)
131 RTCCPTR_DEF ~(X86_CR0_MP)
132 RTCCPTR_DEF 0
133 RTCCPTR_DEF ~(X86_CR0_MP)
134 RTCCPTR_DEF 0
135
136 ;
137 ; Action - switch FPU context and change cr0 flags.
138 ;
139align 16
140hlfpua_switch_fpu_ctx:
141 mov ecx, cr0
142 mov edx, ecx
143 and ecx, [eax*2 + hlfpu_afFlags] ; Calc the new cr0 flags. Do NOT use ECX until we restore it!
144 and edx, ~(X86_CR0_TS | X86_CR0_EM)
145 mov cr0, edx ; Clear flags so we don't trap here.
146
147 test dword [pCpumCpu + CPUMCPU.fUseFlags], CPUM_USED_FPU_HOST
148 jnz hlfpua_host_done
149
150 mov eax, [pCpumCpu + CPUMCPU.Host.fXStateMask]
151 mov pXState, [pCpumCpu + CPUMCPU.Host.pXStateRC]
152 or eax, eax
153 jz hlfpua_host_fxsave
154 mov edx, [pCpumCpu + CPUMCPU.Host.fXStateMask + 4]
155 xsave [pXState]
156 jmp hlfpua_host_done
157hlfpua_host_fxsave:
158 fxsave [pXState]
159hlfpua_host_done:
160
161 mov eax, [pCpumCpu + CPUMCPU.Guest.fXStateMask]
162 mov pXState, [pCpumCpu + CPUMCPU.Guest.pXStateRC]
163 or eax, eax
164 jz hlfpua_guest_fxrstor
165 mov edx, [pCpumCpu + CPUMCPU.Guest.fXStateMask + 4]
166 xrstor [pXState]
167 jmp hlfpua_guest_done
168hlfpua_guest_fxrstor:
169 fxrstor [pXState]
170hlfpua_guest_done:
171
172hlfpua_finished_switch:
173 or dword [pCpumCpu + CPUMCPU.fUseFlags], (CPUM_USED_FPU_HOST | CPUM_USED_FPU_GUEST | CPUM_USED_FPU_SINCE_REM)
174
175 ; Load new CR0 value.
176 mov cr0, ecx ; load the new cr0 flags.
177
178 ; return continue execution.
179 pop esi
180 pop ebx
181 xor eax, eax
182 leave
183 ret
184
185 ;
186 ; Action - Generate Guest trap.
187 ;
188hlfpua_action_4:
189hlfpua_guest_trap:
190 pop esi
191 pop ebx
192 mov eax, VINF_EM_RAW_GUEST_TRAP
193 leave
194 ret
195ENDPROC cpumHandleLazyFPUAsm
196
197
198;;
199; Calls a guest trap/interrupt handler directly
200; Assumes a trap stack frame has already been setup on the guest's stack!
201;
202; @param pRegFrame [esp + 4] Original trap/interrupt context
203; @param selCS [esp + 8] Code selector of handler
204; @param pHandler [esp + 12] GC virtual address of handler
205; @param eflags [esp + 16] Callee's EFLAGS
206; @param selSS [esp + 20] Stack selector for handler
207; @param pEsp [esp + 24] Stack address for handler
208;
209; @remark This call never returns!
210;
211; VMMRCDECL(void) CPUMGCCallGuestTrapHandler(PCPUMCTXCORE pRegFrame, uint32_t selCS, RTGCPTR pHandler, uint32_t eflags, uint32_t selSS, RTGCPTR pEsp);
212align 16
213BEGINPROC_EXPORTED CPUMGCCallGuestTrapHandler
214 mov ebp, esp
215
216 ; construct iret stack frame
217 push dword [ebp + 20] ; SS
218 push dword [ebp + 24] ; ESP
219 push dword [ebp + 16] ; EFLAGS
220 push dword [ebp + 8] ; CS
221 push dword [ebp + 12] ; EIP
222
223 ;
224 ; enable WP
225 ;
226%ifdef ENABLE_WRITE_PROTECTION
227 mov eax, cr0
228 or eax, X86_CR0_WRITE_PROTECT
229 mov cr0, eax
230%endif
231
232 ; restore CPU context (all except cs, eip, ss, esp & eflags; which are restored or overwritten by iret)
233 mov ebp, [ebp + 4] ; pRegFrame
234 mov ebx, [ebp + CPUMCTXCORE.ebx]
235 mov ecx, [ebp + CPUMCTXCORE.ecx]
236 mov edx, [ebp + CPUMCTXCORE.edx]
237 mov esi, [ebp + CPUMCTXCORE.esi]
238 mov edi, [ebp + CPUMCTXCORE.edi]
239
240 ;; @todo load segment registers *before* enabling WP.
241 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_GS | CPUM_HANDLER_CTXCORE_IN_EBP
242 mov gs, [ebp + CPUMCTXCORE.gs.Sel]
243 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_FS | CPUM_HANDLER_CTXCORE_IN_EBP
244 mov fs, [ebp + CPUMCTXCORE.fs.Sel]
245 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_ES | CPUM_HANDLER_CTXCORE_IN_EBP
246 mov es, [ebp + CPUMCTXCORE.es.Sel]
247 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_DS | CPUM_HANDLER_CTXCORE_IN_EBP
248 mov ds, [ebp + CPUMCTXCORE.ds.Sel]
249
250 mov eax, [ebp + CPUMCTXCORE.eax]
251 mov ebp, [ebp + CPUMCTXCORE.ebp]
252
253 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_IRET
254 iret
255ENDPROC CPUMGCCallGuestTrapHandler
256
257
258;;
259; Performs an iret to V86 code
260; Assumes a trap stack frame has already been setup on the guest's stack!
261;
262; @param pRegFrame Original trap/interrupt context
263;
264; This function does not return!
265;
266;VMMRCDECL(void) CPUMGCCallV86Code(PCPUMCTXCORE pRegFrame);
267align 16
268BEGINPROC CPUMGCCallV86Code
269 push ebp
270 mov ebp, esp
271 mov ebx, [ebp + 8] ; pRegFrame
272
273 ; Construct iret stack frame.
274 push dword [ebx + CPUMCTXCORE.gs.Sel]
275 push dword [ebx + CPUMCTXCORE.fs.Sel]
276 push dword [ebx + CPUMCTXCORE.ds.Sel]
277 push dword [ebx + CPUMCTXCORE.es.Sel]
278 push dword [ebx + CPUMCTXCORE.ss.Sel]
279 push dword [ebx + CPUMCTXCORE.esp]
280 push dword [ebx + CPUMCTXCORE.eflags]
281 push dword [ebx + CPUMCTXCORE.cs.Sel]
282 push dword [ebx + CPUMCTXCORE.eip]
283
284 ; Invalidate all segment registers.
285 mov al, ~CPUMSELREG_FLAGS_VALID
286 and [ebx + CPUMCTXCORE.fs.fFlags], al
287 and [ebx + CPUMCTXCORE.ds.fFlags], al
288 and [ebx + CPUMCTXCORE.es.fFlags], al
289 and [ebx + CPUMCTXCORE.ss.fFlags], al
290 and [ebx + CPUMCTXCORE.gs.fFlags], al
291 and [ebx + CPUMCTXCORE.cs.fFlags], al
292
293 ;
294 ; enable WP
295 ;
296%ifdef ENABLE_WRITE_PROTECTION
297 mov eax, cr0
298 or eax, X86_CR0_WRITE_PROTECT
299 mov cr0, eax
300%endif
301
302 ; restore CPU context (all except cs, eip, ss, esp, eflags, ds, es, fs & gs; which are restored or overwritten by iret)
303 mov eax, [ebx + CPUMCTXCORE.eax]
304 mov ecx, [ebx + CPUMCTXCORE.ecx]
305 mov edx, [ebx + CPUMCTXCORE.edx]
306 mov esi, [ebx + CPUMCTXCORE.esi]
307 mov edi, [ebx + CPUMCTXCORE.edi]
308 mov ebp, [ebx + CPUMCTXCORE.ebp]
309 mov ebx, [ebx + CPUMCTXCORE.ebx]
310
311 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_IRET
312 iret
313ENDPROC CPUMGCCallV86Code
314
315
316;;
317; This is a main entry point for resuming (or starting) guest
318; code execution.
319;
320; We get here directly from VMMSwitcher.asm (jmp at the end
321; of VMMSwitcher_HostToGuest).
322;
323; This call never returns!
324;
325; @param edx Pointer to CPUMCPU structure.
326;
327align 16
328BEGINPROC_EXPORTED CPUMGCResumeGuest
329%ifdef VBOX_STRICT
330 ; Call CPUM to check sanity.
331 push edx
332 mov edx, IMP(g_VM)
333 push edx
334 call NAME(CPUMRCAssertPreExecutionSanity)
335 add esp, 4
336 pop edx
337%endif
338
339 ;
340 ; Setup iretd
341 ;
342 push dword [edx + CPUMCPU.Guest.ss.Sel]
343 push dword [edx + CPUMCPU.Guest.esp]
344 push dword [edx + CPUMCPU.Guest.eflags]
345 push dword [edx + CPUMCPU.Guest.cs.Sel]
346 push dword [edx + CPUMCPU.Guest.eip]
347
348 ;
349 ; Restore registers.
350 ;
351 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_ES
352 mov es, [edx + CPUMCPU.Guest.es.Sel]
353 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_FS
354 mov fs, [edx + CPUMCPU.Guest.fs.Sel]
355 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_GS
356 mov gs, [edx + CPUMCPU.Guest.gs.Sel]
357
358%ifdef VBOX_WITH_STATISTICS
359 ;
360 ; Statistics.
361 ;
362 push edx
363 mov edx, IMP(g_VM)
364 lea edx, [edx + VM.StatTotalQemuToGC]
365 STAM_PROFILE_ADV_STOP edx
366
367 mov edx, IMP(g_VM)
368 lea edx, [edx + VM.StatTotalInGC]
369 STAM_PROFILE_ADV_START edx
370 pop edx
371%endif
372
373 ;
374 ; enable WP
375 ;
376%ifdef ENABLE_WRITE_PROTECTION
377 mov eax, cr0
378 or eax, X86_CR0_WRITE_PROTECT
379 mov cr0, eax
380%endif
381
382 ;
383 ; Continue restore.
384 ;
385 mov esi, [edx + CPUMCPU.Guest.esi]
386 mov edi, [edx + CPUMCPU.Guest.edi]
387 mov ebp, [edx + CPUMCPU.Guest.ebp]
388 mov ebx, [edx + CPUMCPU.Guest.ebx]
389 mov ecx, [edx + CPUMCPU.Guest.ecx]
390 mov eax, [edx + CPUMCPU.Guest.eax]
391 push dword [edx + CPUMCPU.Guest.ds.Sel]
392 mov edx, [edx + CPUMCPU.Guest.edx]
393 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_DS
394 pop ds
395
396 ; restart execution.
397 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_IRET
398 iretd
399ENDPROC CPUMGCResumeGuest
400
401
402;;
403; This is a main entry point for resuming (or starting) guest
404; code execution for raw V86 mode
405;
406; We get here directly from VMMSwitcher.asm (jmp at the end
407; of VMMSwitcher_HostToGuest).
408;
409; This call never returns!
410;
411; @param edx Pointer to CPUMCPU structure.
412;
413align 16
414BEGINPROC_EXPORTED CPUMGCResumeGuestV86
415%ifdef VBOX_STRICT
416 ; Call CPUM to check sanity.
417 push edx
418 mov edx, IMP(g_VM)
419 push edx
420 call NAME(CPUMRCAssertPreExecutionSanity)
421 add esp, 4
422 pop edx
423%endif
424
425 ;
426 ; Setup iretd
427 ;
428 push dword [edx + CPUMCPU.Guest.gs.Sel]
429 push dword [edx + CPUMCPU.Guest.fs.Sel]
430 push dword [edx + CPUMCPU.Guest.ds.Sel]
431 push dword [edx + CPUMCPU.Guest.es.Sel]
432
433 push dword [edx + CPUMCPU.Guest.ss.Sel]
434 push dword [edx + CPUMCPU.Guest.esp]
435
436 push dword [edx + CPUMCPU.Guest.eflags]
437 push dword [edx + CPUMCPU.Guest.cs.Sel]
438 push dword [edx + CPUMCPU.Guest.eip]
439
440 ;
441 ; Restore registers.
442 ;
443
444%ifdef VBOX_WITH_STATISTICS
445 ;
446 ; Statistics.
447 ;
448 push edx
449 mov edx, IMP(g_VM)
450 lea edx, [edx + VM.StatTotalQemuToGC]
451 STAM_PROFILE_ADV_STOP edx
452
453 mov edx, IMP(g_VM)
454 lea edx, [edx + VM.StatTotalInGC]
455 STAM_PROFILE_ADV_START edx
456 pop edx
457%endif
458
459 ;
460 ; enable WP
461 ;
462%ifdef ENABLE_WRITE_PROTECTION
463 mov eax, cr0
464 or eax, X86_CR0_WRITE_PROTECT
465 mov cr0, eax
466%endif
467
468 ;
469 ; Continue restore.
470 ;
471 mov esi, [edx + CPUMCPU.Guest.esi]
472 mov edi, [edx + CPUMCPU.Guest.edi]
473 mov ebp, [edx + CPUMCPU.Guest.ebp]
474 mov ecx, [edx + CPUMCPU.Guest.ecx]
475 mov ebx, [edx + CPUMCPU.Guest.ebx]
476 mov eax, [edx + CPUMCPU.Guest.eax]
477 mov edx, [edx + CPUMCPU.Guest.edx]
478
479 ; restart execution.
480 TRPM_NP_GP_HANDLER NAME(cpumRCHandleNPAndGP), CPUM_HANDLER_IRET
481 iretd
482ENDPROC CPUMGCResumeGuestV86
483
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