VirtualBox

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

Last change on this file since 850 was 464, checked in by vboxsync, 18 years ago

Renamed CR4 masks

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