VirtualBox

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

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

The Big Sun Rebranding Header Change

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