VirtualBox

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

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

Correct comment (not pushad any longer).

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