VirtualBox

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

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

warnings

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