VirtualBox

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

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

Don't take any lable addresses we don't have to take as it offends the leopard linker.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.6 KB
Line 
1; $Id: AMD64ToPAE.asm 5693 2007-11-11 17:47:35Z 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 0ffffffffh
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