VirtualBox

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

Last change on this file since 30060 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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