VirtualBox

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

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

Turned dr0..dr7 into an array.

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