VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMSwitcher/AMD64ToPAE.asm@ 4672

Last change on this file since 4672 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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