VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMSwitcher/PAEand32Bit.mac@ 77807

Last change on this file since 77807 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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