VirtualBox

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

Last change on this file since 3020 was 2988, checked in by vboxsync, 17 years ago

InnoTek -> innotek part 4: more miscellaneous files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.8 KB
Line 
1; $Id: PAEand32Bit.mac 2988 2007-06-01 17:36:09Z vboxsync $
2;; @file
3; VMM - World Switchers, template for PAE and 32-Bit.
4;
5
6;
7; Copyright (C) 2006-2007 innotek 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
448 ; call routine
449 pop eax ; call address
450 mov esi, edx ; save edx
451 pop edi ; argument count.
452%ifdef DEBUG_STUFF
453 COM_S_PRINT ';eax='
454 COM_S_DWORD_REG eax
455 COM_S_CHAR ';'
456%endif
457 call eax ; do call
458 add esp, edi ; cleanup stack
459
460 ; return to the host context.
461 push byte 0 ; eip
462 mov edx, esi ; CPUM pointer
463
464%ifdef DEBUG_STUFF
465 COM_S_CHAR '`'
466%endif
467 jmp NAME(VMMGCGuestToHostAsm) ; eax = returncode.
468ENDPROC vmmGCCallTrampoline
469
470
471
472;;
473; The C interface.
474;
475ALIGNCODE(16)
476BEGINPROC vmmGCGuestToHost
477%ifdef DEBUG_STUFF
478 push esi
479 COM_NEWLINE
480 DEBUG_CHAR('b')
481 DEBUG_CHAR('a')
482 DEBUG_CHAR('c')
483 DEBUG_CHAR('k')
484 DEBUG_CHAR('!')
485 COM_NEWLINE
486 pop esi
487%endif
488 mov eax, [esp + 4]
489 jmp NAME(VMMGCGuestToHostAsm)
490ENDPROC vmmGCGuestToHost
491
492
493;;
494; VMMGCGuestToHostAsmGuestCtx
495;
496; Switches from Guest Context to Host Context.
497; Of course it's only called from within the GC.
498;
499; @param eax Return code.
500; @param esp + 4 Pointer to CPUMCTXCORE.
501;
502; @remark ASSUMES interrupts disabled.
503;
504ALIGNCODE(16)
505BEGINPROC VMMGCGuestToHostAsmGuestCtx
506 DEBUG_CHAR('~')
507
508%ifdef VBOX_WITH_STATISTICS
509 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalInGC
510 mov edx, 0ffffffffh
511 STAM_PROFILE_ADV_STOP edx
512
513 FIXUP FIX_GC_VM_OFF, 1, VM.StatTotalGCToQemu
514 mov edx, 0ffffffffh
515 STAM_PROFILE_ADV_START edx
516
517 FIXUP FIX_GC_VM_OFF, 1, VM.StatSwitcherToHC
518 mov edx, 0ffffffffh
519 STAM_PROFILE_ADV_START edx
520%endif
521
522 ;
523 ; Load the CPUM pointer.
524 ;
525 FIXUP FIX_GC_CPUM_OFF, 1, 0
526 mov edx, 0ffffffffh
527
528 ; Skip return address (assumes called!)
529 lea esp, [esp + 4]
530
531 ;
532 ; Guest Context (assumes esp now points to CPUMCTXCORE structure).
533 ;
534 ; general purpose registers (layout is pushad)
535 push eax
536
537 ; @todo do a rep movsd instead
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