VirtualBox

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

Last change on this file since 21942 was 21942, checked in by vboxsync, 15 years ago

VMM: detect syscall usage on the host.

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