VirtualBox

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

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

Moved guest and host CPU contexts into per-VCPU array.

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