VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMSwitcher/PAEand32Bit.mac@ 4593

Last change on this file since 4593 was 4593, checked in by vboxsync, 17 years ago

Don't modify the X86_CR4_VMXE flag.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.7 KB
Line 
1; $Id: PAEand32Bit.mac 4593 2007-09-07 08:01:32Z vboxsync $
2;; @file
3; VMM - World Switchers, template for PAE and 32-Bit.
4;
5
6;
7; Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13; in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14; distribution. VirtualBox OSE is distributed in the hope that it will
15; be useful, but WITHOUT ANY WARRANTY of any kind.
16
17;%define DEBUG_STUFF 1
18
19;*******************************************************************************
20;* Header Files *
21;*******************************************************************************
22%include "VBox/asmdefs.mac"
23%include "VBox/x86.mac"
24%include "VBox/cpum.mac"
25%include "VBox/stam.mac"
26%include "VBox/vm.mac"
27%include "CPUMInternal.mac"
28%include "VMMSwitcher/VMMSwitcher.mac"
29
30%undef NEED_ID
31%ifdef NEED_PAE_ON_32BIT_HOST
32%define NEED_ID
33%endif
34%ifdef NEED_32BIT_ON_PAE_HOST
35%define NEED_ID
36%endif
37
38
39
40;
41; Start the fixup records
42; We collect the fixups in the .data section as we go along
43; It is therefore VITAL that no-one is using the .data section
44; for anything else between 'Start' and 'End'.
45;
46BEGINDATA
47GLOBALNAME Fixups
48
49
50
51BEGINCODE
52GLOBALNAME Start
53
54;;
55; The C interface.
56;
57BEGINPROC vmmR0HostToGuest
58
59%ifdef DEBUG_STUFF
60 COM_S_NEWLINE
61 COM_S_CHAR '^'
62%endif
63
64%ifdef VBOX_WITH_STATISTICS
65 ;
66 ; Switcher stats.
67 ;
68 FIXUP FIX_HC_VM_OFF, 1, VM.StatSwitcherToGC
69 mov edx, 0ffffffffh
70 STAM_PROFILE_ADV_START edx
71%endif
72
73 ;
74 ; Call worker.
75 ;
76 FIXUP FIX_HC_CPUM_OFF, 1, 0
77 mov edx, 0ffffffffh
78 push cs ; allow for far return and restore cs correctly.
79 call NAME(vmmR0HostToGuestAsm)
80
81%ifdef VBOX_WITH_STATISTICS
82 ;
83 ; Switcher stats.
84 ;
85 FIXUP FIX_HC_VM_OFF, 1, VM.StatSwitcherToHC
86 mov edx, 0ffffffffh
87 STAM_PROFILE_ADV_STOP edx
88%endif
89
90 ret
91ENDPROC vmmR0HostToGuest
92
93
94
95; *****************************************************************************
96; vmmR0HostToGuestAsm
97;
98; Phase one of the switch from host to guest context (host MMU context)
99;
100; INPUT:
101; - edx virtual address of CPUM structure (valid in host context)
102;
103; USES/DESTROYS:
104; - eax, ecx, edx
105;
106; ASSUMPTION:
107; - current CS and DS selectors are wide open
108;
109; *****************************************************************************
110ALIGNCODE(16)
111BEGINPROC vmmR0HostToGuestAsm
112 ;;
113 ;; Save CPU host context
114 ;; Skip eax, edx and ecx as these are not preserved over calls.
115 ;;
116 ; general registers.
117 mov [edx + CPUM.Host.ebx], ebx
118 mov [edx + CPUM.Host.edi], edi
119 mov [edx + CPUM.Host.esi], esi
120 mov [edx + CPUM.Host.esp], esp
121 mov [edx + CPUM.Host.ebp], ebp
122 ; selectors.
123 mov [edx + CPUM.Host.ds], ds
124 mov [edx + CPUM.Host.es], es
125 mov [edx + CPUM.Host.fs], fs
126 mov [edx + CPUM.Host.gs], gs
127 mov [edx + CPUM.Host.ss], ss
128 ; special registers.
129 sldt [edx + CPUM.Host.ldtr]
130 sidt [edx + CPUM.Host.idtr]
131 sgdt [edx + CPUM.Host.gdtr]
132 str [edx + CPUM.Host.tr]
133 ; flags
134 pushfd
135 pop dword [edx + CPUM.Host.eflags]
136
137 FIXUP FIX_NO_SYSENTER_JMP, 0, htg_no_sysenter - NAME(Start) ; this will insert a jmp htg_no_sysenter if host doesn't use sysenter.
138 ; save MSR_IA32_SYSENTER_CS register.
139 mov ecx, MSR_IA32_SYSENTER_CS
140 mov ebx, edx ; save edx
141 rdmsr ; edx:eax <- MSR[ecx]
142 mov [ebx + CPUM.Host.SysEnter.cs], eax
143 mov [ebx + CPUM.Host.SysEnter.cs + 4], edx
144 xor eax, eax ; load 0:0 to cause #GP upon sysenter
145 xor edx, edx
146 wrmsr
147 xchg ebx, edx ; restore edx
148 jmp short htg_no_sysenter
149
150ALIGNCODE(16)
151htg_no_sysenter:
152
153 ;; handle use flags.
154 mov esi, [edx + CPUM.fUseFlags] ; esi == use flags.
155 and esi, ~CPUM_USED_FPU ; Clear CPUM_USED_* flags. ;;@todo FPU check can be optimized to use cr0 flags!
156 mov [edx + CPUM.fUseFlags], esi
157
158 ; debug registers.
159 test esi, CPUM_USE_DEBUG_REGS | CPUM_USE_DEBUG_REGS_HOST
160 jz htg_debug_regs_no
161 jmp htg_debug_regs_save_dr7and6
162htg_debug_regs_no:
163
164 ; control registers.
165 mov eax, cr0
166 mov [edx + CPUM.Host.cr0], eax
167 ;mov eax, cr2 ; assume host os don't suff things in cr2. (safe)
168 ;mov [edx + CPUM.Host.cr2], eax
169 mov eax, cr3
170 mov [edx + CPUM.Host.cr3], eax
171 mov eax, cr4
172 mov [edx + CPUM.Host.cr4], eax
173
174 ;;
175 ;; Start switching to VMM context.
176 ;;
177
178 ;
179 ; Change CR0 and CR4 so we can correctly emulate FPU/MMX/SSE[23] exceptions
180 ; Also disable WP. (eax==cr4 now)
181 ; Note! X86_CR4_PSE and X86_CR4_PAE are important if the host thinks so :-)
182 ; Note! X86_CR4_VMXE must not be touched in case the CPU is in vmx root mode
183 ;
184 and eax, X86_CR4_MCE | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_VMXE
185 mov ecx, [edx + CPUM.Guest.cr4]
186 ;; @todo Switcher cleanup: Determin base CR4 during CPUMR0Init / VMMR3SelectSwitcher putting it
187 ; in CPUM.Hyper.cr4 (which isn't currently being used). That should
188 ; simplify this operation a bit (and improve locality of the data).
189
190 ;
191 ; CR4.AndMask and CR4.OrMask are set in CPUMR3Init based on the presence of
192 ; FXSAVE support on the host CPU
193 ;
194 and ecx, [edx + CPUM.CR4.AndMask]
195 or eax, ecx
196 or eax, [edx + CPUM.CR4.OrMask]
197 mov cr4, eax
198
199 mov eax, [edx + CPUM.Guest.cr0]
200 and eax, X86_CR0_EM
201 or eax, X86_CR0_PE | X86_CR0_PG | X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP
202 mov cr0, eax
203
204 ; Load new gdt so we can do far jump to guest code after cr3 reload.
205 lgdt [edx + CPUM.Hyper.gdtr]
206 DEBUG_CHAR('1') ; trashes esi
207
208 ;;
209 ;; Load Intermediate memory context.
210 ;;
211 FIXUP SWITCHER_FIX_INTER_CR3_HC, 1
212 mov eax, 0ffffffffh
213 mov cr3, eax
214 DEBUG_CHAR('2') ; trashes esi
215
216%ifdef NEED_ID
217 ;;
218 ;; Jump to identity mapped location
219 ;;
220 FIXUP FIX_HC_2_ID_NEAR_REL, 1, NAME(IDEnterTarget) - NAME(Start)
221 jmp near NAME(IDEnterTarget)
222
223 ; We're now on identity mapped pages!
224ALIGNCODE(16)
225GLOBALNAME IDEnterTarget
226 DEBUG_CHAR('3')
227 mov edx, cr4
228%ifdef NEED_PAE_ON_32BIT_HOST
229 or edx, X86_CR4_PAE
230%else
231 and edx, ~X86_CR4_PAE
232%endif
233 mov eax, cr0
234 and eax, ~X86_CR0_PG
235 mov cr0, eax
236 DEBUG_CHAR('4')
237 mov cr4, edx
238 FIXUP SWITCHER_FIX_INTER_CR3_GC, 1
239 mov edx, 0ffffffffh
240 mov cr3, edx
241 or eax, X86_CR0_PG
242 DEBUG_CHAR('5')
243 mov cr0, eax
244 DEBUG_CHAR('6')
245%endif
246
247 ;;
248 ;; Jump to guest code mapping of the code and load the Hypervisor CS.
249 ;;
250 FIXUP FIX_GC_FAR32, 1, NAME(FarJmpGCTarget) - NAME(Start)
251 jmp 0fff8h:0deadfaceh
252
253
254 ;;
255 ;; When we arrive at this label we're at the
256 ;; guest code mapping of the switching code.
257 ;;
258ALIGNCODE(16)
259GLOBALNAME FarJmpGCTarget
260 DEBUG_CHAR('-')
261 ; load final cr3 and do far jump to load cs.
262 FIXUP SWITCHER_FIX_HYPER_CR3, 1
263 mov eax, 0ffffffffh
264 mov cr3, eax
265 DEBUG_CHAR('0')
266
267 ;;
268 ;; We're in VMM MMU context and VMM CS is loaded.
269 ;; Setup the rest of the VMM state.
270 ;;
271 FIXUP FIX_GC_CPUM_OFF, 1, 0
272 mov edx, 0ffffffffh
273 ; Activate guest IDT
274 DEBUG_CHAR('1')
275 lidt [edx + CPUM.Hyper.idtr]
276 ; Load selectors
277 DEBUG_CHAR('2')
278 FIXUP FIX_HYPER_DS, 1
279 mov eax, 0ffffh
280 mov ds, eax
281 mov es, eax
282 xor eax, eax
283 mov gs, eax
284 mov fs, eax
285
286 ; Setup stack
287 DEBUG_CHAR('3')
288 lss esp, [edx + CPUM.Hyper.esp]
289
290 ; Restore TSS selector; must mark it as not busy before using ltr (!)
291 DEBUG_CHAR('4')
292 FIXUP FIX_GC_TSS_GDTE_DW2, 2
293 and dword [0ffffffffh], ~0200h ; clear busy flag (2nd type2 bit)
294 DEBUG_CHAR('5')
295 ltr word [edx + CPUM.Hyper.tr]
296 DEBUG_CHAR('6')
297
298 ; Activate the ldt (now we can safely crash).
299 lldt [edx + CPUM.Hyper.ldtr]
300 DEBUG_CHAR('7')
301
302 ;; use flags.
303 mov esi, [edx + CPUM.fUseFlags]
304
305 ; debug registers
306 test esi, CPUM_USE_DEBUG_REGS
307 jz htg_debug_regs_guest_no
308 jmp htg_debug_regs_guest
309htg_debug_regs_guest_no:
310 DEBUG_CHAR('9')
311
312%ifdef VBOX_WITH_NMI
313 ;
314 ; Setup K7 NMI.
315 ;
316 mov esi, edx
317 ; clear all PerfEvtSeln registers
318 xor eax, eax
319 xor edx, edx
320 mov ecx, MSR_K7_PERFCTR0
321 wrmsr
322 mov ecx, MSR_K7_PERFCTR1
323 wrmsr
324 mov ecx, MSR_K7_PERFCTR2
325 wrmsr
326 mov ecx, MSR_K7_PERFCTR3
327 wrmsr
328
329 mov eax, BIT(20) | BIT(17) | BIT(16) | 076h
330 mov ecx, MSR_K7_EVNTSEL0
331 wrmsr
332 mov eax, 02329B000h
333 mov edx, 0fffffffeh ; -1.6GHz * 5
334 mov ecx, MSR_K7_PERFCTR0
335 wrmsr
336
337 FIXUP FIX_GC_APIC_BASE_32BIT, 1
338 mov eax, 0f0f0f0f0h
339 add eax, 0340h ; APIC_LVTPC
340 mov dword [eax], 0400h ; APIC_DM_NMI
341
342 xor edx, edx
343 mov eax, BIT(20) | BIT(17) | BIT(16) | 076h | BIT(22) ;+EN
344 mov ecx, MSR_K7_EVNTSEL0
345 wrmsr
346
347 mov edx, esi
348%endif
349
350 ; General registers.
351 mov ebx, [edx + CPUM.Hyper.ebx]
352 mov ebp, [edx + CPUM.Hyper.ebp]
353 mov esi, [edx + CPUM.Hyper.esi]
354 mov edi, [edx + CPUM.Hyper.edi]
355 push dword [edx + CPUM.Hyper.eflags]
356 popfd
357 DEBUG_CHAR('!')
358
359 ;;
360 ;; Return to the VMM code which either called the switcher or
361 ;; the code set up to run by HC.
362 ;;
363%ifdef DEBUG_STUFF
364 COM_S_PRINT ';eip='
365 mov eax, [edx + CPUM.Hyper.eip]
366 COM_S_DWORD_REG eax
367 COM_S_CHAR ';'
368%endif
369 mov eax, [edx + CPUM.Hyper.eip]
370%ifdef VBOX_WITH_STATISTICS
371 FIXUP FIX_GC_VM_OFF, 1, VM.StatSwitcherToGC
372 mov edx, 0ffffffffh
373 STAM_PROFILE_ADV_STOP edx
374 FIXUP FIX_GC_CPUM_OFF, 1, 0
375 mov edx, 0ffffffffh
376%endif
377 jmp eax
378
379;;
380; Detour for saving the host DR7 and DR6.
381; esi and edx must be preserved.
382htg_debug_regs_save_dr7and6:
383DEBUG_S_CHAR('s');
384 mov eax, dr7 ; not sure, but if I read the docs right this will trap if GD is set. FIXME!!!
385 mov [edx + CPUM.Host.dr7], eax
386 xor eax, eax ; clear everything. (bit 12? is read as 1...)
387 mov dr7, eax
388 mov eax, dr6 ; just in case we save the state register too.
389 mov [edx + CPUM.Host.dr6], eax
390 jmp htg_debug_regs_no
391
392;;
393; Detour for saving host DR0-3 and loading hypervisor debug registers.
394; esi and edx must be preserved.
395htg_debug_regs_guest:
396 DEBUG_S_CHAR('D')
397 DEBUG_S_CHAR('R')
398 DEBUG_S_CHAR('x')
399 ; save host DR0-3.
400 mov eax, dr0
401 mov [edx + CPUM.Host.dr0], eax
402 mov ebx, dr1
403 mov [edx + CPUM.Host.dr1], ebx
404 mov ecx, dr2
405 mov [edx + CPUM.Host.dr2], ecx
406 mov eax, dr3
407 mov [edx + CPUM.Host.dr3], eax
408 ; load hyper DR0-7
409 mov ebx, [edx + CPUM.Hyper.dr0]
410 mov dr0, ebx
411 mov ecx, [edx + CPUM.Hyper.dr1]
412 mov dr1, ecx
413 mov eax, [edx + CPUM.Hyper.dr2]
414 mov dr2, eax
415 mov ebx, [edx + CPUM.Hyper.dr3]
416 mov dr3, ebx
417 ;mov eax, [edx + CPUM.Hyper.dr6]
418 mov ecx, 0ffff0ff0h
419 mov dr6, ecx
420 mov eax, [edx + CPUM.Hyper.dr7]
421 mov dr7, eax
422 jmp htg_debug_regs_guest_no
423
424ENDPROC vmmR0HostToGuestAsm
425
426
427;;
428; Trampoline for doing a call when starting the hyper visor execution.
429;
430; Push any arguments to the routine.
431; Push the argument frame size (cArg * 4).
432; Push the call target (_cdecl convention).
433; Push the address of this routine.
434;
435;
436ALIGNCODE(16)
437BEGINPROC vmmGCCallTrampoline
438%ifdef DEBUG_STUFF
439 COM_S_CHAR 'c'
440 COM_S_CHAR 't'
441 COM_S_CHAR '!'
442%endif
443
444 ; call routine
445 pop eax ; call address
446 mov esi, edx ; save edx
447 pop edi ; argument count.
448%ifdef DEBUG_STUFF
449 COM_S_PRINT ';eax='
450 COM_S_DWORD_REG eax
451 COM_S_CHAR ';'
452%endif
453 call eax ; do call
454 add esp, edi ; cleanup stack
455
456 ; return to the host context.
457 push byte 0 ; eip
458 mov edx, esi ; CPUM pointer
459
460%ifdef DEBUG_STUFF
461 COM_S_CHAR '`'
462%endif
463 jmp NAME(VMMGCGuestToHostAsm) ; eax = returncode.
464ENDPROC vmmGCCallTrampoline
465
466
467
468;;
469; The C interface.
470;
471ALIGNCODE(16)
472BEGINPROC vmmGCGuestToHost
473%ifdef DEBUG_STUFF
474 push esi
475 COM_NEWLINE
476 DEBUG_CHAR('b')
477 DEBUG_CHAR('a')
478 DEBUG_CHAR('c')
479 DEBUG_CHAR('k')
480 DEBUG_CHAR('!')
481 COM_NEWLINE
482 pop esi
483%endif
484 mov eax, [esp + 4]
485 jmp NAME(VMMGCGuestToHostAsm)
486ENDPROC vmmGCGuestToHost
487
488
489;;
490; VMMGCGuestToHostAsmGuestCtx
491;
492; Switches from Guest Context to Host Context.
493; Of course it's only called from within the GC.
494;
495; @param eax Return code.
496; @param esp + 4 Pointer to CPUMCTXCORE.
497;
498; @remark ASSUMES interrupts disabled.
499;
500ALIGNCODE(16)
501BEGINPROC VMMGCGuestToHostAsmGuestCtx
502 DEBUG_CHAR('~')
503
504%ifdef VBOX_WITH_STATISTICS
505 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalInGC
506 mov edx, 0ffffffffh
507 STAM_PROFILE_ADV_STOP edx
508
509 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalGCToQemu
510 mov edx, 0ffffffffh
511 STAM_PROFILE_ADV_START edx
512
513 FIXUP FIX_GC_VM_OFF, 1, VM.StatSwitcherToHC
514 mov edx, 0ffffffffh
515 STAM_PROFILE_ADV_START edx
516%endif
517
518 ;
519 ; Load the CPUM pointer.
520 ;
521 FIXUP FIX_GC_CPUM_OFF, 1, 0
522 mov edx, 0ffffffffh
523
524 ; Skip return address (assumes called!)
525 lea esp, [esp + 4]
526
527 ;
528 ; Guest Context (assumes esp now points to CPUMCTXCORE structure).
529 ;
530 ; general purpose registers (layout is pushad)
531 push eax
532
533 ; @todo do a rep movsd instead
534 mov eax, [esp + 4 + CPUMCTXCORE.eax]
535 mov [edx + CPUM.Guest.eax], eax
536 mov eax, [esp + 4 + CPUMCTXCORE.ecx]
537 mov [edx + CPUM.Guest.ecx], eax
538 mov eax, [esp + 4 + CPUMCTXCORE.edx]
539 mov [edx + CPUM.Guest.edx], eax
540 mov eax, [esp + 4 + CPUMCTXCORE.ebx]
541 mov [edx + CPUM.Guest.ebx], eax
542 mov eax, [esp + 4 + CPUMCTXCORE.esp]
543 mov [edx + CPUM.Guest.esp], eax
544 mov eax, [esp + 4 + CPUMCTXCORE.ebp]
545 mov [edx + CPUM.Guest.ebp], eax
546 mov eax, [esp + 4 + CPUMCTXCORE.esi]
547 mov [edx + CPUM.Guest.esi], eax
548 mov eax, [esp + 4 + CPUMCTXCORE.edi]
549 mov [edx + CPUM.Guest.edi], eax
550 mov eax, dword [esp + 4 + CPUMCTXCORE.es]
551 mov dword [edx + CPUM.Guest.es], eax
552 mov eax, dword [esp + 4 + CPUMCTXCORE.cs]
553 mov dword [edx + CPUM.Guest.cs], eax
554 mov eax, dword [esp + 4 + CPUMCTXCORE.ss]
555 mov dword [edx + CPUM.Guest.ss], eax
556 mov eax, dword [esp + 4 + CPUMCTXCORE.ds]
557 mov dword [edx + CPUM.Guest.ds], eax
558 mov eax, dword [esp + 4 + CPUMCTXCORE.fs]
559 mov dword [edx + CPUM.Guest.fs], eax
560 mov eax, dword [esp + 4 + CPUMCTXCORE.gs]
561 mov dword [edx + CPUM.Guest.gs], eax
562 mov eax, [esp + 4 + CPUMCTXCORE.eflags]
563 mov dword [edx + CPUM.Guest.eflags], eax
564 mov eax, [esp + 4 + CPUMCTXCORE.eip]
565 mov dword [edx + CPUM.Guest.eip], eax
566 pop eax
567
568 add esp, CPUMCTXCORE_size ; skip CPUMCTXCORE structure
569
570 jmp vmmGCGuestToHostAsm_EIPDone
571ENDPROC VMMGCGuestToHostAsmGuestCtx
572
573
574;;
575; VMMGCGuestToHostAsmHyperCtx
576;
577; This is an alternative entry point which we'll be using
578; when the we have the hypervisor context and need to save
579; that before going to the host.
580;
581; This is typically useful when abandoning the hypervisor
582; because of a trap and want the trap state to be saved.
583;
584; @param eax Return code.
585; @param ecx Points to CPUMCTXCORE.
586; @uses eax,edx,ecx
587ALIGNCODE(16)
588BEGINPROC VMMGCGuestToHostAsmHyperCtx
589 DEBUG_CHAR('#')
590
591%ifdef VBOX_WITH_STATISTICS
592 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalInGC
593 mov edx, 0ffffffffh
594 STAM_PROFILE_ADV_STOP edx
595
596 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalGCToQemu
597 mov edx, 0ffffffffh
598 STAM_PROFILE_ADV_START edx
599
600 FIXUP FIX_GC_VM_OFF, 1, VM.StatSwitcherToHC
601 mov edx, 0ffffffffh
602 STAM_PROFILE_ADV_START edx
603%endif
604
605 ;
606 ; Load the CPUM pointer.
607 ;
608 FIXUP FIX_GC_CPUM_OFF, 1, 0
609 mov edx, 0ffffffffh
610
611 push eax ; save return code.
612 ; general purpose registers
613 mov eax, [ecx + CPUMCTXCORE.edi]
614 mov [edx + CPUM.Hyper.edi], eax
615 mov eax, [ecx + CPUMCTXCORE.esi]
616 mov [edx + CPUM.Hyper.esi], eax
617 mov eax, [ecx + CPUMCTXCORE.ebp]
618 mov [edx + CPUM.Hyper.ebp], eax
619 mov eax, [ecx + CPUMCTXCORE.eax]
620 mov [edx + CPUM.Hyper.eax], eax
621 mov eax, [ecx + CPUMCTXCORE.ebx]
622 mov [edx + CPUM.Hyper.ebx], eax
623 mov eax, [ecx + CPUMCTXCORE.edx]
624 mov [edx + CPUM.Hyper.edx], eax
625 mov eax, [ecx + CPUMCTXCORE.ecx]
626 mov [edx + CPUM.Hyper.ecx], eax
627 mov eax, [ecx + CPUMCTXCORE.esp]
628 mov [edx + CPUM.Hyper.esp], eax
629 ; selectors
630 mov eax, [ecx + CPUMCTXCORE.ss]
631 mov [edx + CPUM.Hyper.ss], eax
632 mov eax, [ecx + CPUMCTXCORE.gs]
633 mov [edx + CPUM.Hyper.gs], eax
634 mov eax, [ecx + CPUMCTXCORE.fs]
635 mov [edx + CPUM.Hyper.fs], eax
636 mov eax, [ecx + CPUMCTXCORE.es]
637 mov [edx + CPUM.Hyper.es], eax
638 mov eax, [ecx + CPUMCTXCORE.ds]
639 mov [edx + CPUM.Hyper.ds], eax
640 mov eax, [ecx + CPUMCTXCORE.cs]
641 mov [edx + CPUM.Hyper.cs], eax
642 ; flags
643 mov eax, [ecx + CPUMCTXCORE.eflags]
644 mov [edx + CPUM.Hyper.eflags], eax
645 ; eip
646 mov eax, [ecx + CPUMCTXCORE.eip]
647 mov [edx + CPUM.Hyper.eip], eax
648 ; jump to common worker code.
649 pop eax ; restore return code.
650 jmp vmmGCGuestToHostAsm_SkipHyperRegs
651
652ENDPROC VMMGCGuestToHostAsmHyperCtx
653
654
655;;
656; VMMGCGuestToHostAsm
657;
658; This is an alternative entry point which we'll be using
659; when the we have saved the guest state already or we haven't
660; been messing with the guest at all.
661;
662; @param eax Return code.
663; @uses eax, edx, ecx (or it may use them in the future)
664;
665ALIGNCODE(16)
666BEGINPROC VMMGCGuestToHostAsm
667 DEBUG_CHAR('%')
668
669%ifdef VBOX_WITH_STATISTICS
670 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalInGC
671 mov edx, 0ffffffffh
672 STAM_PROFILE_ADV_STOP edx
673
674 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalGCToQemu
675 mov edx, 0ffffffffh
676 STAM_PROFILE_ADV_START edx
677
678 FIXUP FIX_GC_VM_OFF, 1, VM.StatSwitcherToHC
679 mov edx, 0ffffffffh
680 STAM_PROFILE_ADV_START edx
681%endif
682
683 ;
684 ; Load the CPUM pointer.
685 ;
686 FIXUP FIX_GC_CPUM_OFF, 1, 0
687 mov edx, 0ffffffffh
688
689 pop dword [edx + CPUM.Hyper.eip] ; call return from stack
690 jmp short vmmGCGuestToHostAsm_EIPDone
691
692ALIGNCODE(16)
693vmmGCGuestToHostAsm_EIPDone:
694 ; general registers which we care about.
695 mov dword [edx + CPUM.Hyper.ebx], ebx
696 mov dword [edx + CPUM.Hyper.esi], esi
697 mov dword [edx + CPUM.Hyper.edi], edi
698 mov dword [edx + CPUM.Hyper.ebp], ebp
699 mov dword [edx + CPUM.Hyper.esp], esp
700
701 ; special registers which may change.
702vmmGCGuestToHostAsm_SkipHyperRegs:
703 ; str [edx + CPUM.Hyper.tr] - double fault only, and it won't be right then either.
704 sldt [edx + CPUM.Hyper.ldtr]
705
706 ; No need to save CRx here. They are set dynamically according to Guest/Host requirements.
707 ; FPU context is saved before restore of host saving (another) branch.
708
709%ifdef VBOX_WITH_NMI
710 ;
711 ; Disarm K7 NMI.
712 ;
713 mov esi, edx
714 mov edi, eax
715
716 xor edx, edx
717 xor eax, eax
718 mov ecx, MSR_K7_EVNTSEL0
719 wrmsr
720
721 mov eax, edi
722 mov edx, esi
723%endif
724
725
726 ;;
727 ;; Load Intermediate memory context.
728 ;;
729 mov edi, eax ; save return code in EDI (careful with COM_DWORD_REG from here on!)
730 mov ecx, [edx + CPUM.Host.cr3]
731 FIXUP SWITCHER_FIX_INTER_CR3_GC, 1
732 mov eax, 0ffffffffh
733 mov cr3, eax
734 DEBUG_CHAR('?')
735
736 ;; We're now in intermediate memory context!
737%ifdef NEED_ID
738 ;;
739 ;; Jump to identity mapped location
740 ;;
741 FIXUP FIX_GC_2_ID_NEAR_REL, 1, NAME(IDExitTarget) - NAME(Start)
742 jmp near NAME(IDExitTarget)
743
744 ; We're now on identity mapped pages!
745ALIGNCODE(16)
746GLOBALNAME IDExitTarget
747 DEBUG_CHAR('1')
748 mov edx, cr4
749%ifdef NEED_PAE_ON_32BIT_HOST
750 and edx, ~X86_CR4_PAE
751%else
752 or edx, X86_CR4_PAE
753%endif
754 mov eax, cr0
755 and eax, ~X86_CR0_PG
756 mov cr0, eax
757 DEBUG_CHAR('2')
758 mov cr4, edx
759 FIXUP SWITCHER_FIX_INTER_CR3_HC, 1
760 mov edx, 0ffffffffh
761 mov cr3, edx
762 or eax, X86_CR0_PG
763 DEBUG_CHAR('3')
764 mov cr0, eax
765 DEBUG_CHAR('4')
766
767 ;;
768 ;; Jump to HC mapping.
769 ;;
770 FIXUP FIX_ID_2_HC_NEAR_REL, 1, NAME(HCExitTarget) - NAME(Start)
771 jmp near NAME(HCExitTarget)
772%else
773 ;;
774 ;; Jump to HC mapping.
775 ;;
776 FIXUP FIX_GC_2_HC_NEAR_REL, 1, NAME(HCExitTarget) - NAME(Start)
777 jmp near NAME(HCExitTarget)
778%endif
779
780
781 ;
782 ; When we arrive here we're at the host context
783 ; mapping of the switcher code.
784 ;
785ALIGNCODE(16)
786GLOBALNAME HCExitTarget
787 DEBUG_CHAR('9')
788 ; load final cr3
789 mov cr3, ecx
790 DEBUG_CHAR('@')
791
792
793 ;;
794 ;; Restore Host context.
795 ;;
796 ; Load CPUM pointer into edx
797 FIXUP FIX_HC_CPUM_OFF, 1, 0
798 mov edx, 0ffffffffh
799 ; activate host gdt and idt
800 lgdt [edx + CPUM.Host.gdtr]
801 DEBUG_CHAR('0')
802 lidt [edx + CPUM.Host.idtr]
803 DEBUG_CHAR('1')
804 ; Restore TSS selector; must mark it as not busy before using ltr (!)
805%if 1 ; ASSUME that this is supposed to be 'BUSY'. (saves 20-30 ticks on the T42p)
806 movzx eax, word [edx + CPUM.Host.tr] ; eax <- TR
807 and al, 0F8h ; mask away TI and RPL bits, get descriptor offset.
808 add eax, [edx + CPUM.Host.gdtr + 2] ; eax <- GDTR.address + descriptor offset.
809 and dword [eax + 4], ~0200h ; clear busy flag (2nd type2 bit)
810 ltr word [edx + CPUM.Host.tr]
811%else
812 movzx eax, word [edx + CPUM.Host.tr] ; eax <- TR
813 and al, 0F8h ; mask away TI and RPL bits, get descriptor offset.
814 add eax, [edx + CPUM.Host.gdtr + 2] ; eax <- GDTR.address + descriptor offset.
815 mov ecx, [eax + 4] ; ecx <- 2nd descriptor dword
816 mov ebx, ecx ; save orginal value
817 and ecx, ~0200h ; clear busy flag (2nd type2 bit)
818 mov [eax + 4], ecx ; not using xchg here is paranoia..
819 ltr word [edx + CPUM.Host.tr]
820 xchg [eax + 4], ebx ; using xchg is paranoia too...
821%endif
822 ; activate ldt
823 DEBUG_CHAR('2')
824 lldt [edx + CPUM.Host.ldtr]
825 ; Restore segment registers
826 mov eax, [edx + CPUM.Host.ds]
827 mov ds, eax
828 mov eax, [edx + CPUM.Host.es]
829 mov es, eax
830 mov eax, [edx + CPUM.Host.fs]
831 mov fs, eax
832 mov eax, [edx + CPUM.Host.gs]
833 mov gs, eax
834 ; restore stack
835 lss esp, [edx + CPUM.Host.esp]
836
837
838 FIXUP FIX_NO_SYSENTER_JMP, 0, gth_sysenter_no - NAME(Start) ; this will insert a jmp gth_sysenter_no if host doesn't use sysenter.
839 ; restore MSR_IA32_SYSENTER_CS register.
840 mov ecx, MSR_IA32_SYSENTER_CS
841 mov eax, [edx + CPUM.Host.SysEnter.cs]
842 mov ebx, [edx + CPUM.Host.SysEnter.cs + 4]
843 xchg edx, ebx ; save/load edx
844 wrmsr ; MSR[ecx] <- edx:eax
845 xchg edx, ebx ; restore edx
846 jmp short gth_sysenter_no
847
848ALIGNCODE(16)
849gth_sysenter_no:
850
851 ;; @todo AMD syscall
852
853 ; Restore FPU if guest has used it.
854 ; Using fxrstor should ensure that we're not causing unwanted exception on the host.
855 mov esi, [edx + CPUM.fUseFlags] ; esi == use flags.
856 test esi, CPUM_USED_FPU
857 jz near gth_fpu_no
858 mov ecx, cr0
859 and ecx, ~(X86_CR0_TS | X86_CR0_EM)
860 mov cr0, ecx
861
862 FIXUP FIX_NO_FXSAVE_JMP, 0, gth_no_fxsave - NAME(Start) ; this will insert a jmp gth_no_fxsave if fxsave isn't supported.
863 fxsave [edx + CPUM.Guest.fpu]
864 fxrstor [edx + CPUM.Host.fpu]
865 jmp near gth_fpu_no
866
867gth_no_fxsave:
868 fnsave [edx + CPUM.Guest.fpu]
869 mov eax, [edx + CPUM.Host.fpu] ; control word
870 not eax ; 1 means exception ignored (6 LS bits)
871 and eax, byte 03Fh ; 6 LS bits only
872 test eax, [edx + CPUM.Host.fpu + 4] ; status word
873 jz gth_no_exceptions_pending
874
875 ; technically incorrect, but we certainly don't want any exceptions now!!
876 and dword [edx + CPUM.Host.fpu + 4], ~03Fh
877
878gth_no_exceptions_pending:
879 frstor [edx + CPUM.Host.fpu]
880 jmp short gth_fpu_no
881
882ALIGNCODE(16)
883gth_fpu_no:
884
885 ; Control registers.
886 ; Would've liked to have these highere up in case of crashes, but
887 ; the fpu stuff must be done before we restore cr0.
888 mov ecx, [edx + CPUM.Host.cr4]
889 mov cr4, ecx
890 mov ecx, [edx + CPUM.Host.cr0]
891 mov cr0, ecx
892 ;mov ecx, [edx + CPUM.Host.cr2] ; assumes this is waste of time.
893 ;mov cr2, ecx
894
895 ; restore debug registers (if modified) (esi must still be fUseFlags!)
896 ; (must be done after cr4 reload because of the debug extension.)
897 test esi, CPUM_USE_DEBUG_REGS | CPUM_USE_DEBUG_REGS_HOST
898 jz short gth_debug_regs_no
899 jmp gth_debug_regs_restore
900gth_debug_regs_no:
901
902 ; restore general registers.
903 mov eax, edi ; restore return code. eax = return code !!
904 mov edi, [edx + CPUM.Host.edi]
905 mov esi, [edx + CPUM.Host.esi]
906 mov ebx, [edx + CPUM.Host.ebx]
907 mov ebp, [edx + CPUM.Host.ebp]
908 push dword [edx + CPUM.Host.eflags]
909 popfd
910
911%ifdef DEBUG_STUFF
912; COM_S_CHAR '4'
913%endif
914 retf
915
916;;
917; Detour for restoring the host debug registers.
918; edx and edi must be preserved.
919gth_debug_regs_restore:
920 DEBUG_S_CHAR('d')
921 xor eax, eax
922 mov dr7, eax ; paranoia or not?
923 test esi, CPUM_USE_DEBUG_REGS
924 jz short gth_debug_regs_dr7
925 DEBUG_S_CHAR('r')
926 mov eax, [edx + CPUM.Host.dr0]
927 mov dr0, eax
928 mov ebx, [edx + CPUM.Host.dr1]
929 mov dr1, ebx
930 mov ecx, [edx + CPUM.Host.dr2]
931 mov dr2, ecx
932 mov eax, [edx + CPUM.Host.dr3]
933 mov dr3, eax
934gth_debug_regs_dr7:
935 mov ebx, [edx + CPUM.Host.dr6]
936 mov dr6, ebx
937 mov ecx, [edx + CPUM.Host.dr7]
938 mov dr7, ecx
939 jmp gth_debug_regs_no
940
941ENDPROC VMMGCGuestToHostAsm
942
943
944GLOBALNAME End
945;
946; The description string (in the text section).
947;
948NAME(Description):
949 db SWITCHER_DESCRIPTION
950 db 0
951
952extern NAME(Relocate)
953
954;
955; End the fixup records.
956;
957BEGINDATA
958 db FIX_THE_END ; final entry.
959GLOBALNAME FixupsEnd
960
961;;
962; The switcher definition structure.
963ALIGNDATA(16)
964GLOBALNAME Def
965 istruc VMMSWITCHERDEF
966 at VMMSWITCHERDEF.pvCode, RTCCPTR_DEF NAME(Start)
967 at VMMSWITCHERDEF.pvFixups, RTCCPTR_DEF NAME(Fixups)
968 at VMMSWITCHERDEF.pszDesc, RTCCPTR_DEF NAME(Description)
969 at VMMSWITCHERDEF.pfnRelocate, RTCCPTR_DEF NAME(Relocate)
970 at VMMSWITCHERDEF.enmType, dd SWITCHER_TYPE
971 at VMMSWITCHERDEF.cbCode, dd NAME(End) - NAME(Start)
972 at VMMSWITCHERDEF.offR0HostToGuest, dd NAME(vmmR0HostToGuest) - NAME(Start)
973 at VMMSWITCHERDEF.offGCGuestToHost, dd NAME(vmmGCGuestToHost) - NAME(Start)
974 at VMMSWITCHERDEF.offGCCallTrampoline, dd NAME(vmmGCCallTrampoline) - NAME(Start)
975 at VMMSWITCHERDEF.offGCGuestToHostAsm, dd NAME(VMMGCGuestToHostAsm) - NAME(Start)
976 at VMMSWITCHERDEF.offGCGuestToHostAsmHyperCtx, dd NAME(VMMGCGuestToHostAsmHyperCtx)- NAME(Start)
977 at VMMSWITCHERDEF.offGCGuestToHostAsmGuestCtx, dd NAME(VMMGCGuestToHostAsmGuestCtx)- NAME(Start)
978 ; disasm help
979 at VMMSWITCHERDEF.offHCCode0, dd 0
980%ifdef NEED_ID
981 at VMMSWITCHERDEF.cbHCCode0, dd NAME(IDEnterTarget) - NAME(Start)
982%else
983 at VMMSWITCHERDEF.cbHCCode0, dd NAME(FarJmpGCTarget) - NAME(Start)
984%endif
985 at VMMSWITCHERDEF.offHCCode1, dd NAME(HCExitTarget) - NAME(Start)
986 at VMMSWITCHERDEF.cbHCCode1, dd NAME(End) - NAME(HCExitTarget)
987%ifdef NEED_ID
988 at VMMSWITCHERDEF.offIDCode0, dd NAME(IDEnterTarget) - NAME(Start)
989 at VMMSWITCHERDEF.cbIDCode0, dd NAME(FarJmpGCTarget) - NAME(IDEnterTarget)
990 at VMMSWITCHERDEF.offIDCode1, dd NAME(IDExitTarget) - NAME(Start)
991 at VMMSWITCHERDEF.cbIDCode1, dd NAME(HCExitTarget) - NAME(IDExitTarget)
992%else
993 at VMMSWITCHERDEF.offIDCode0, dd 0
994 at VMMSWITCHERDEF.cbIDCode0, dd 0
995 at VMMSWITCHERDEF.offIDCode1, dd 0
996 at VMMSWITCHERDEF.cbIDCode1, dd 0
997%endif
998 at VMMSWITCHERDEF.offGCCode, dd NAME(FarJmpGCTarget) - NAME(Start)
999%ifdef NEED_ID
1000 at VMMSWITCHERDEF.cbGCCode, dd NAME(IDExitTarget) - NAME(FarJmpGCTarget)
1001%else
1002 at VMMSWITCHERDEF.cbGCCode, dd NAME(HCExitTarget) - NAME(FarJmpGCTarget)
1003%endif
1004
1005 iend
1006
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