VirtualBox

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

Last change on this file since 16774 was 14192, checked in by vboxsync, 16 years ago

VMM: fixed a regression introduced by r38992 (tstVMM failed during HW breakpoint test)

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