VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMSwitcher/AMD64andLegacy.mac@ 45786

Last change on this file since 45786 was 41985, checked in by vboxsync, 12 years ago

VMM: Fixed tstVMM (single stepping ++ in raw-mode code).

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