VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/TRPMRCHandlersA.asm@ 69146

Last change on this file since 69146 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 46.5 KB
Line 
1; $Id: TRPMRCHandlersA.asm 69111 2017-10-17 14:26:02Z vboxsync $
2;; @file
3; TRPM - Raw-mode Context Trap Handlers
4;
5
6;
7; Copyright (C) 2006-2017 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;*******************************************************************************
19;* Header Files *
20;*******************************************************************************
21%include "VMMRC.mac"
22%include "iprt/x86.mac"
23%include "VBox/vmm/cpum.mac"
24%include "VBox/vmm/stam.mac"
25%include "VBox/vmm/vm.mac"
26%include "TRPMInternal.mac"
27%include "VBox/err.mac"
28%include "VBox/vmm/trpm.mac"
29
30
31;*******************************************************************************
32;* External Symbols *
33;*******************************************************************************
34extern IMPNAME(g_TRPM) ; These IMPNAME(g_*) symbols resolve to the import table
35extern IMPNAME(g_TRPMCPU) ; where there is a pointer to the real symbol. PE imports
36extern IMPNAME(g_VM) ; are a bit confusing at first... :-)
37extern IMPNAME(g_trpmGuestCtxCore)
38extern IMPNAME(g_trpmHyperCtxCore)
39extern NAME(trpmRCTrapInGeneric)
40extern NAME(TRPMGCTrap01Handler)
41extern NAME(TRPMGCHyperTrap01Handler)
42%ifdef VBOX_WITH_NMI
43extern NAME(TRPMGCTrap02Handler)
44extern NAME(TRPMGCHyperTrap02Handler)
45%endif
46extern NAME(TRPMGCTrap03Handler)
47extern NAME(TRPMGCHyperTrap03Handler)
48extern NAME(TRPMGCTrap06Handler)
49extern NAME(TRPMGCTrap07Handler)
50extern NAME(TRPMGCTrap0bHandler)
51extern NAME(TRPMGCHyperTrap0bHandler)
52extern NAME(TRPMGCTrap0dHandler)
53extern NAME(TRPMGCHyperTrap0dHandler)
54extern NAME(TRPMGCTrap0eHandler)
55extern NAME(TRPMGCHyperTrap0eHandler)
56extern NAME(CPUMRCAssertPreExecutionSanity)
57
58
59;*******************************************************************************
60;* Defined Constants And Macros *
61;*******************************************************************************
62;; Some conditional COM port debugging.
63;%define DEBUG_STUFF 1
64;%define DEBUG_STUFF_TRPG 1
65;%define DEBUG_STUFF_INT 1
66
67
68BEGINCODE
69
70;;
71; Jump table for trap handlers for hypervisor traps.
72;
73g_apfnStaticTrapHandlersHyper:
74 ; N - M M - T - C - D i
75 ; o - n o - y - o - e p
76 ; - e n - p - d - s t
77 ; - i - e - e - c .
78 ; - c - - - r
79 ; =============================================================
80 dd 0 ; 0 - #DE - F - N - Divide error
81 dd NAME(TRPMGCHyperTrap01Handler) ; 1 - #DB - F/T - N - Single step, INT 1 instruction
82%ifdef VBOX_WITH_NMI
83 dd NAME(TRPMGCHyperTrap02Handler) ; 2 - - I - N - Non-Maskable Interrupt (NMI)
84%else
85 dd 0 ; 2 - - I - N - Non-Maskable Interrupt (NMI)
86%endif
87 dd NAME(TRPMGCHyperTrap03Handler) ; 3 - #BP - T - N - Breakpoint, INT 3 instruction.
88 dd 0 ; 4 - #OF - T - N - Overflow, INTO instruction.
89 dd 0 ; 5 - #BR - F - N - BOUND Range Exceeded, BOUND instruction.
90 dd 0 ; 6 - #UD - F - N - Undefined(/Invalid) Opcode.
91 dd 0 ; 7 - #NM - F - N - Device not available, FP or (F)WAIT instruction.
92 dd 0 ; 8 - #DF - A - 0 - Double fault.
93 dd 0 ; 9 - - F - N - Coprocessor Segment Overrun (obsolete).
94 dd 0 ; a - #TS - F - Y - Invalid TSS, Taskswitch or TSS access.
95 dd NAME(TRPMGCHyperTrap0bHandler) ; b - #NP - F - Y - Segment not present.
96 dd 0 ; c - #SS - F - Y - Stack-Segment fault.
97 dd NAME(TRPMGCHyperTrap0dHandler) ; d - #GP - F - Y - General protection fault.
98 dd NAME(TRPMGCHyperTrap0eHandler) ; e - #PF - F - Y - Page fault.
99 dd 0 ; f - - - - Intel Reserved. Do not use.
100 dd 0 ; 10 - #MF - F - N - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction.
101 dd 0 ; 11 - #AC - F - 0 - Alignment Check.
102 dd 0 ; 12 - #MC - A - N - Machine Check.
103 dd 0 ; 13 - #XF - F - N - SIMD Floating-Point Exception.
104 dd 0 ; 14 - - - - Intel Reserved. Do not use.
105 dd 0 ; 15 - - - - Intel Reserved. Do not use.
106 dd 0 ; 16 - - - - Intel Reserved. Do not use.
107 dd 0 ; 17 - - - - Intel Reserved. Do not use.
108 dd 0 ; 18 - - - - Intel Reserved. Do not use.
109
110
111;;
112; Jump table for trap handlers for guest traps
113;
114g_apfnStaticTrapHandlersGuest:
115 ; N - M M - T - C - D i
116 ; o - n o - y - o - e p
117 ; - e n - p - d - s t
118 ; - i - e - e - c .
119 ; - c - - - r
120 ; =============================================================
121 dd 0 ; 0 - #DE - F - N - Divide error
122 dd NAME(TRPMGCTrap01Handler) ; 1 - #DB - F/T - N - Single step, INT 1 instruction
123%ifdef VBOX_WITH_NMI
124 dd NAME(TRPMGCTrap02Handler) ; 2 - - I - N - Non-Maskable Interrupt (NMI)
125%else
126 dd 0 ; 2 - - I - N - Non-Maskable Interrupt (NMI)
127%endif
128 dd NAME(TRPMGCTrap03Handler) ; 3 - #BP - T - N - Breakpoint, INT 3 instruction.
129 dd 0 ; 4 - #OF - T - N - Overflow, INTO instruction.
130 dd 0 ; 5 - #BR - F - N - BOUND Range Exceeded, BOUND instruction.
131 dd NAME(TRPMGCTrap06Handler) ; 6 - #UD - F - N - Undefined(/Invalid) Opcode.
132 dd NAME(TRPMGCTrap07Handler) ; 7 - #NM - F - N - Device not available, FP or (F)WAIT instruction.
133 dd 0 ; 8 - #DF - A - 0 - Double fault.
134 dd 0 ; 9 - - F - N - Coprocessor Segment Overrun (obsolete).
135 dd 0 ; a - #TS - F - Y - Invalid TSS, Taskswitch or TSS access.
136 dd NAME(TRPMGCTrap0bHandler) ; b - #NP - F - Y - Segment not present.
137 dd 0 ; c - #SS - F - Y - Stack-Segment fault.
138 dd NAME(TRPMGCTrap0dHandler) ; d - #GP - F - Y - General protection fault.
139 dd NAME(TRPMGCTrap0eHandler) ; e - #PF - F - Y - Page fault.
140 dd 0 ; f - - - - Intel Reserved. Do not use.
141 dd 0 ; 10 - #MF - F - N - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction.
142 dd 0 ; 11 - #AC - F - 0 - Alignment Check.
143 dd 0 ; 12 - #MC - A - N - Machine Check.
144 dd 0 ; 13 - #XF - F - N - SIMD Floating-Point Exception.
145 dd 0 ; 14 - - - - Intel Reserved. Do not use.
146 dd 0 ; 15 - - - - Intel Reserved. Do not use.
147 dd 0 ; 16 - - - - Intel Reserved. Do not use.
148 dd 0 ; 17 - - - - Intel Reserved. Do not use.
149 dd 0 ; 18 - - - - Intel Reserved. Do not use.
150
151
152
153;;
154; We start by 24 push <vector no.> + jmp <generic entry point>
155;
156ALIGNCODE(16)
157BEGINPROC_EXPORTED TRPMGCHandlerGeneric
158%macro TRPMGenericEntry 1
159 db 06ah, i ; push imm8 - note that this is a signextended value.
160 jmp %1
161 ALIGNCODE(8)
162%assign i i+1
163%endmacro
164
165%assign i 0 ; start counter.
166 TRPMGenericEntry GenericTrap ; 0
167 TRPMGenericEntry GenericTrap ; 1
168 TRPMGenericEntry GenericTrap ; 2
169 TRPMGenericEntry GenericTrap ; 3
170 TRPMGenericEntry GenericTrap ; 4
171 TRPMGenericEntry GenericTrap ; 5
172 TRPMGenericEntry GenericTrap ; 6
173 TRPMGenericEntry GenericTrap ; 7
174 TRPMGenericEntry GenericTrapErrCode ; 8
175 TRPMGenericEntry GenericTrap ; 9
176 TRPMGenericEntry GenericTrapErrCode ; a
177 TRPMGenericEntry GenericTrapErrCode ; b
178 TRPMGenericEntry GenericTrapErrCode ; c
179 TRPMGenericEntry GenericTrapErrCode ; d
180 TRPMGenericEntry GenericTrapErrCode ; e
181 TRPMGenericEntry GenericTrap ; f (reserved)
182 TRPMGenericEntry GenericTrap ; 10
183 TRPMGenericEntry GenericTrapErrCode ; 11
184 TRPMGenericEntry GenericTrap ; 12
185 TRPMGenericEntry GenericTrap ; 13
186 TRPMGenericEntry GenericTrap ; 14 (reserved)
187 TRPMGenericEntry GenericTrap ; 15 (reserved)
188 TRPMGenericEntry GenericTrap ; 16 (reserved)
189 TRPMGenericEntry GenericTrap ; 17 (reserved)
190%undef i
191%undef TRPMGenericEntry
192
193;;
194; Main exception handler for the guest context
195;
196; Stack:
197; 14 SS
198; 10 ESP
199; c EFLAGS
200; 8 CS
201; 4 EIP
202; 0 vector number
203;
204; @uses none
205;
206ALIGNCODE(8)
207GenericTrap:
208 ;
209 ; for the present we fake an error code ~0
210 ;
211 push eax
212 mov eax, 0ffffffffh
213 xchg [esp + 4], eax ; get vector number, set error code
214 xchg [esp], eax ; get saved eax, set vector number
215 jmp short GenericTrapErrCode
216
217
218;;
219; Main exception handler for the guest context with error code
220;
221; Stack:
222; 28 GS (V86 only)
223; 24 FS (V86 only)
224; 20 DS (V86 only)
225; 1C ES (V86 only)
226; 18 SS (only if ring transition.)
227; 14 ESP (only if ring transition.)
228; 10 EFLAGS
229; c CS
230; 8 EIP
231; 4 Error code. (~0 for vectors which don't take an error code.)
232; 0 vector number
233;
234; Error code:
235;
236; 31 16 15 3 2 1 0
237;
238; reserved segment TI IDT EXT
239; selector GDT/LDT (1) IDT External interrupt
240; index (IDT=0) index
241;
242; NOTE: Page faults (trap 14) have a different error code
243;
244; @uses none
245;
246ALIGNCODE(8)
247GenericTrapErrCode:
248 cld
249
250 ;
251 ; Save ds, es, fs, gs, eax and ebx so we have a context pointer (ebx) and
252 ; scratch (eax) register to work with. A sideeffect of using ebx is that
253 ; it's preserved accross cdecl calls.
254 ;
255 ; In order to safely access data, we need to load our flat DS & ES selector,
256 ; clear FS and GS (stale guest selector prevention), and clear make sure
257 ; that CR0.WP is cleared.
258 ;
259 push ds ; +14h
260 push es ; +10h
261 push fs ; +0ch
262 push gs ; +08h
263 push eax ; +04h
264 push ebx ; +00h
265%push StackFrame
266%define %$STK_SAVED_EBX esp
267%define %$STK_SAVED_EAX esp + 04h
268%define %$STK_SAVED_GS esp + 08h
269%define %$STK_SAVED_FS esp + 0ch
270%define %$STK_SAVED_ES esp + 10h
271%define %$STK_SAVED_DS esp + 14h
272%define %$ESPOFF 18h
273%define %$STK_VECTOR esp + 00h + %$ESPOFF
274%define %$STK_ERRCD esp + 04h + %$ESPOFF
275%define %$STK_EIP esp + 08h + %$ESPOFF
276%define %$STK_CS esp + 0ch + %$ESPOFF
277%define %$STK_EFLAGS esp + 10h + %$ESPOFF
278%define %$STK_ESP esp + 14h + %$ESPOFF
279%define %$STK_SS esp + 18h + %$ESPOFF
280%define %$STK_V86_ES esp + 1ch + %$ESPOFF
281%define %$STK_V86_DS esp + 20h + %$ESPOFF
282%define %$STK_V86_FS esp + 24h + %$ESPOFF
283%define %$STK_V86_GS esp + 28h + %$ESPOFF
284
285 mov bx, ss ; load
286 mov ds, bx
287 mov es, bx
288
289 xor bx, bx ; load 0 into gs and fs.
290 mov gs, bx
291 mov fs, bx
292
293 mov eax, cr0 ;; @todo elimitate this read?
294 and eax, ~X86_CR0_WRITE_PROTECT
295 mov cr0, eax
296
297 mov ebx, IMP(g_trpmGuestCtxCore) ; Assume GC as the most common.
298 test byte [%$STK_CS], 3h ; check RPL of the cs selector
299 jnz .save_guest_state
300 test dword [%$STK_EFLAGS], X86_EFL_VM; If in V86, then guest.
301 jnz .save_guest_state
302 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
303
304 ;
305 ; Save the state.
306 ;
307.save_hyper_state:
308 mov [ebx + CPUMCTXCORE.ecx], ecx
309 lea eax, [%$STK_ESP]
310 mov [ebx + CPUMCTXCORE.esp], eax
311 mov cx, ss
312 mov [ebx + CPUMCTXCORE.ss.Sel], cx
313 jmp .save_state_common
314
315.save_guest_state:
316 mov [ebx + CPUMCTXCORE.ecx], ecx
317 mov eax, [%$STK_ESP]
318 mov [ebx + CPUMCTXCORE.esp], eax
319 mov cx, [%$STK_SS]
320 mov [ebx + CPUMCTXCORE.ss.Sel], cx
321
322.save_state_common:
323 mov eax, [%$STK_SAVED_EAX]
324 mov [ebx + CPUMCTXCORE.eax], eax
325 mov [ebx + CPUMCTXCORE.edx], edx
326 mov eax, [%$STK_SAVED_EBX]
327 mov [ebx + CPUMCTXCORE.ebx], eax
328 mov [ebx + CPUMCTXCORE.esi], esi
329 mov [ebx + CPUMCTXCORE.edi], edi
330 mov [ebx + CPUMCTXCORE.ebp], ebp
331
332 mov cx, [%$STK_CS]
333 mov [ebx + CPUMCTXCORE.cs.Sel], cx
334 mov eax, [%$STK_EIP]
335 mov [ebx + CPUMCTXCORE.eip], eax
336 mov eax, [%$STK_EFLAGS]
337 mov [ebx + CPUMCTXCORE.eflags], eax
338
339%if GC_ARCH_BITS == 64 ; zero out the high dwords - probably not necessary any more.
340 mov dword [ebx + CPUMCTXCORE.eax + 4], 0
341 mov dword [ebx + CPUMCTXCORE.ecx + 4], 0
342 mov dword [ebx + CPUMCTXCORE.edx + 4], 0
343 mov dword [ebx + CPUMCTXCORE.ebx + 4], 0
344 mov dword [ebx + CPUMCTXCORE.esi + 4], 0
345 mov dword [ebx + CPUMCTXCORE.edi + 4], 0
346 mov dword [ebx + CPUMCTXCORE.ebp + 4], 0
347 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
348 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
349%endif
350
351 test dword [%$STK_EFLAGS], X86_EFL_VM
352 jnz .save_V86_segregs
353
354 mov cx, [%$STK_SAVED_ES]
355 mov [ebx + CPUMCTXCORE.es.Sel], cx
356 mov cx, [%$STK_SAVED_DS]
357 mov [ebx + CPUMCTXCORE.ds.Sel], cx
358 mov cx, [%$STK_SAVED_FS]
359 mov [ebx + CPUMCTXCORE.fs.Sel], cx
360 mov cx, [%$STK_SAVED_GS]
361 mov [ebx + CPUMCTXCORE.gs.Sel], cx
362 jmp .done_saving
363
364 ;
365 ; The DS, ES, FS and GS registers are zeroed in V86 mode and their real
366 ; values are on the stack.
367 ;
368.save_V86_segregs:
369 mov cx, [%$STK_V86_ES]
370 mov [ebx + CPUMCTXCORE.es.Sel], cx
371 mov cx, [%$STK_V86_DS]
372 mov [ebx + CPUMCTXCORE.ds.Sel], cx
373 mov cx, [%$STK_V86_FS]
374 mov [ebx + CPUMCTXCORE.fs.Sel], cx
375 mov cx, [%$STK_V86_GS]
376 mov [ebx + CPUMCTXCORE.gs.Sel], cx
377
378.done_saving:
379
380%ifdef VBOX_WITH_STATISTICS
381 ;
382 ; Start profiling.
383 ;
384 mov edx, [%$STK_VECTOR]
385 imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128.
386 add edx, TRPM.aStatGCTraps
387 add edx, IMP(g_TRPM)
388 STAM_PROFILE_ADV_START edx
389%endif
390
391 ;
392 ; Store the information about the active trap/interrupt.
393 ;
394 mov esi, IMP(g_TRPMCPU) ; esi = TRPMCPU until resume!
395 movzx edx, byte [%$STK_VECTOR]
396 mov [esi + TRPMCPU.uActiveVector], edx
397 mov edx, [%$STK_ERRCD]
398 mov [esi + TRPMCPU.uActiveErrorCode], edx
399 mov dword [esi + TRPMCPU.enmActiveType], TRPM_TRAP
400 mov edx, cr2 ;; @todo Check how expensive cr2 reads are!
401 mov dword [esi + TRPMCPU.uActiveCR2], edx
402%if GC_ARCH_BITS == 64 ; zero out the high dwords.
403 mov dword [esi + TRPMCPU.uActiveErrorCode + 4], 0
404 mov dword [esi + TRPMCPU.uActiveCR2 + 4], 0
405%endif
406
407 ;
408 ; Check if we're in the raw-mode context (RC / hypervisor) when this happened.
409 ;
410 test dword [%$STK_EFLAGS], X86_EFL_VM
411 jnz short .gc_not_raw_mode_context
412
413 test byte [%$STK_CS], 3h ; check RPL of the cs selector
414 jz .rc_in_raw_mode_context
415
416 ;
417 ; Trap in guest code.
418 ;
419.gc_not_raw_mode_context:
420%ifdef DEBUG_STUFF_TRPG
421 mov eax, [%$STK_ERRCD]
422 mov ecx, 'trpG' ; indicate trap.
423 mov edx, [%$STK_VECTOR]
424 call trpmDbgDumpRegisterFrame
425%endif
426
427 ;
428 ; Do we have a GC handler for these traps?
429 ;
430 mov edx, [%$STK_VECTOR]
431 mov eax, [g_apfnStaticTrapHandlersGuest + edx * 4]
432 or eax, eax
433 jnz short .gc_have_static_handler
434 mov eax, VINF_EM_RAW_GUEST_TRAP
435 jmp short .gc_guest_trap
436
437 ;
438 ; Call static handler.
439 ;
440.gc_have_static_handler:
441 push ebx ; Param 2 - CPUMCTXCORE pointer.
442 push esi ; Param 1 - Pointer to TRPMCPU.
443 call eax
444 add esp, byte 8 ; cleanup stack (cdecl)
445 or eax, eax
446 je near .gc_continue_guest
447
448 ;
449 ; Switch back to the host and process it there.
450 ;
451.gc_guest_trap:
452%ifdef VBOX_WITH_STATISTICS
453 mov edx, [%$STK_VECTOR]
454 imul edx, edx, byte STAMPROFILEADV_size ; assume < 128
455 add edx, IMP(g_TRPM)
456 add edx, TRPM.aStatGCTraps
457 STAM_PROFILE_ADV_STOP edx
458%endif
459 mov edx, IMP(g_VM)
460 call [edx + VM.pfnVMMRCToHostAsm]
461
462 ; We shouldn't ever return this way. So, raise a special IPE if we do.
463.gc_panic_again:
464 mov eax, VERR_TRPM_IPE_3
465 mov edx, IMP(g_VM)
466 call [edx + VM.pfnVMMRCToHostAsm]
467 jmp .gc_panic_again
468
469 ;
470 ; Continue(/Resume/Restart/Whatever) guest execution.
471 ;
472ALIGNCODE(16)
473.gc_continue_guest:
474%ifdef VBOX_WITH_STATISTICS
475 mov edx, [%$STK_VECTOR]
476 imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128
477 add edx, TRPM.aStatGCTraps
478 add edx, IMP(g_TRPM)
479 STAM_PROFILE_ADV_STOP edx
480%endif
481
482%ifdef VBOX_STRICT
483 ; Call CPUM to check sanity.
484 mov edx, IMP(g_VM)
485 push edx
486 call NAME(CPUMRCAssertPreExecutionSanity)
487 add esp, 4
488%endif
489
490 ; For v8086 mode we must branch off before we enable write protection.
491 test dword [ebx + CPUMCTXCORE.eflags], X86_EFL_VM
492 jnz .gc_V86_return
493
494 ; enable WP
495 mov eax, cr0 ;; @todo try elimiate this read.
496 or eax, X86_CR0_WRITE_PROTECT
497 mov cr0, eax
498
499 ; restore guest state and start executing again.
500 mov eax, [ebx + CPUMCTXCORE.eax]
501 mov [%$STK_SAVED_EAX], eax
502 mov ecx, [ebx + CPUMCTXCORE.ecx]
503 mov edx, [ebx + CPUMCTXCORE.edx]
504 mov eax, [ebx + CPUMCTXCORE.ebx]
505 mov [%$STK_SAVED_EBX], eax
506 mov ebp, [ebx + CPUMCTXCORE.ebp]
507 mov esi, [ebx + CPUMCTXCORE.esi]
508 mov edi, [ebx + CPUMCTXCORE.edi]
509
510 mov eax, [ebx + CPUMCTXCORE.esp]
511 mov [%$STK_ESP], eax
512 mov eax, dword [ebx + CPUMCTXCORE.ss.Sel]
513 mov [%$STK_SS], eax
514 mov eax, [ebx + CPUMCTXCORE.eflags]
515 mov [%$STK_EFLAGS], eax
516 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
517 mov [%$STK_CS], eax
518 mov eax, [ebx + CPUMCTXCORE.eip]
519 mov [%$STK_EIP], eax
520
521 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
522 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
523 mov gs, ax
524
525 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
526 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
527 mov fs, ax
528
529 mov ax, [ebx + CPUMCTXCORE.es.Sel]
530 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
531 mov es, ax
532
533 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
534 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
535 mov ds, ax
536
537 ; finally restore our scratch register eax and ebx.
538 pop ebx
539 pop eax
540 add esp, 16 + 8 ; skip segregs, error code, and vector number.
541
542 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET
543 iret
544
545ALIGNCODE(16)
546.gc_V86_return:
547 ;
548 ; We may be returning to V8086 while having entered from protected mode!
549 ; So, we have to push the whole stack frame. There's code in CPUMRC that
550 ; does exactly that, so call it instead of duplicating it.
551 ;
552 push ebx
553 extern NAME(CPUMGCCallV86Code)
554 call NAME(CPUMGCCallV86Code)
555 int3 ; doesn't return...
556
557
558 ;
559 ; Trap in Hypervisor, try to handle it.
560 ;
561 ; (eax = pTRPMCPU)
562 ;
563ALIGNCODE(16)
564.rc_in_raw_mode_context:
565 ; fix ss:esp.
566 lea ecx, [%$STK_ESP] ; calc esp at trap
567 mov [ebx + CPUMCTXCORE.esp], ecx; update esp in register frame
568 mov [ebx + CPUMCTXCORE.ss.Sel], ss ; update ss in register frame
569
570 ; check for temporary handler.
571 movzx edx, byte [esi + TRPMCPU.uActiveVector]
572 mov edi, IMP(g_TRPM)
573 xor ecx, ecx
574 xchg ecx, [edi + TRPM.aTmpTrapHandlers + edx * 4] ; ecx = Temp handler pointer or 0
575 or ecx, ecx
576 jnz short .rc_have_temporary_handler
577
578 ; check for static trap handler.
579 mov ecx, [g_apfnStaticTrapHandlersHyper + edx * 4] ; ecx = Static handler pointer or 0
580 or ecx, ecx
581 jnz short .rc_have_static_handler
582 jmp .rc_abandon_ship
583
584
585 ;
586 ; Temporary trap handler present, call it (CDECL).
587 ;
588.rc_have_temporary_handler:
589 push ebx ; Param 2 - Pointer to CPUMCTXCORE.
590 push IMP(g_VM) ; Param 1 - Pointer to VM.
591 call ecx
592 add esp, byte 8 ; cleanup stack (cdecl)
593
594 cmp eax, byte VINF_SUCCESS ; If completely handled Then resume execution.
595 je near .rc_continue
596 jmp .rc_abandon_ship
597
598
599 ;
600 ; Static trap handler present, call it (CDECL).
601 ;
602.rc_have_static_handler:
603 push ebx ; Param 2 - Pointer to CPUMCTXCORE.
604 push esi ; Param 1 - Pointer to TRPMCPU
605 call ecx
606 add esp, byte 8 ; cleanup stack (cdecl)
607
608 cmp eax, byte VINF_SUCCESS ; If completely handled Then resume execution.
609 je short .rc_continue
610 cmp eax, VINF_EM_DBG_HYPER_STEPPED
611 je short .rc_to_host
612 cmp eax, VINF_EM_DBG_HYPER_BREAKPOINT
613 je short .rc_to_host
614 cmp eax, VINF_EM_DBG_HYPER_ASSERTION
615 je short .rc_to_host
616 jmp .rc_abandon_ship
617
618 ;
619 ; Pop back to the host to service the error.
620 ;
621.rc_to_host:
622 mov edx, IMP(g_VM)
623 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
624 mov eax, VERR_TRPM_DONT_PANIC
625 jmp .rc_to_host
626
627 ;
628 ; Continue(/Resume/Restart/Whatever) hypervisor execution.
629 ; Don't reset the TRPM state. Caller takes care of that.
630 ;
631ALIGNCODE(16)
632.rc_continue:
633%ifdef DEBUG_STUFF
634 mov eax, [%$STK_ERRCD]
635 mov ecx, 'resH' ; indicate trap.
636 mov edx, [%$STK_VECTOR]
637 call trpmDbgDumpRegisterFrame
638%endif
639
640%ifdef VBOX_WITH_STATISTICS
641 mov edx, [%$STK_VECTOR]
642 imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128
643 add edx, TRPM.aStatGCTraps
644 add edx, IMP(g_TRPM)
645 STAM_PROFILE_ADV_STOP edx
646%endif
647
648 ; restore
649 mov eax, [ebx + CPUMCTXCORE.eax]
650 mov [%$STK_SAVED_EAX], eax
651 mov ecx, [ebx + CPUMCTXCORE.ecx]
652 mov edx, [ebx + CPUMCTXCORE.edx]
653 mov eax, [ebx + CPUMCTXCORE.ebx]
654 mov [%$STK_SAVED_EBX], eax
655 mov ebp, [ebx + CPUMCTXCORE.ebp]
656 mov esi, [ebx + CPUMCTXCORE.esi]
657 mov edi, [ebx + CPUMCTXCORE.edi]
658
659 ; skipping esp & ss.
660
661 mov eax, [ebx + CPUMCTXCORE.eflags]
662 mov [%$STK_EFLAGS], eax
663 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
664 mov [%$STK_CS], eax
665 mov eax, [ebx + CPUMCTXCORE.eip]
666 mov [%$STK_EIP], eax
667
668 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
669 mov gs, ax
670
671 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
672 mov fs, ax
673
674 mov ax, [ebx + CPUMCTXCORE.es.Sel]
675 mov es, ax
676
677 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
678 mov ds, ax
679
680 ; finally restore our scratch register eax and ebx.
681 pop ebx
682 pop eax
683 add esp, 16 + 8 ; skip segregs, error code, and vector number.
684
685 iret
686
687
688 ;
689 ; Internal processing error - don't panic, start meditating!
690 ;
691.rc_abandon_ship:
692%ifdef DEBUG_STUFF
693 mov eax, [%$STK_ERRCD]
694 mov ecx, 'trpH' ; indicate trap.
695 mov edx, [%$STK_VECTOR]
696 call trpmDbgDumpRegisterFrame
697%endif
698
699.rc_do_not_panic:
700 mov edx, IMP(g_VM)
701 mov eax, VERR_TRPM_DONT_PANIC
702 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
703%ifdef DEBUG_STUFF
704 COM_S_PRINT 'bad!!!'
705%endif
706 jmp .rc_do_not_panic ; this shall never ever happen!
707%pop
708ENDPROC TRPMGCHandlerGeneric
709
710
711
712
713
714;;
715; We start by 256 push <vector no.> + jmp interruptworker
716;
717ALIGNCODE(16)
718BEGINPROC_EXPORTED TRPMGCHandlerInterupt
719 ; NASM has some nice features, here an example of a loop.
720%assign i 0
721%rep 256
722 db 06ah, i ; push imm8 - note that this is a signextended value.
723 jmp ti_GenericInterrupt
724 ALIGNCODE(8)
725%assign i i+1
726%endrep
727
728;;
729; Main interrupt handler for the guest context
730;
731; Stack:
732; 24 GS (V86 only)
733; 20 FS (V86 only)
734; 1C DS (V86 only)
735; 18 ES (V86 only)
736; 14 SS
737; 10 ESP
738; c EFLAGS
739; 8 CS
740; 4 EIP
741; ESP -> 0 Vector number (only use low byte!).
742;
743; @uses none
744ti_GenericInterrupt:
745 cld
746
747 ;
748 ; Save ds, es, fs, gs, eax and ebx so we have a context pointer (ebx) and
749 ; scratch (eax) register to work with. A sideeffect of using ebx is that
750 ; it's preserved accross cdecl calls.
751 ;
752 ; In order to safely access data, we need to load our flat DS & ES selector,
753 ; clear FS and GS (stale guest selector prevention), and clear make sure
754 ; that CR0.WP is cleared.
755 ;
756 push ds ; +14h
757 push es ; +10h
758 push fs ; +0ch
759 push gs ; +08h
760 push eax ; +04h
761 push ebx ; +00h
762%push StackFrame
763%define %$STK_SAVED_EBX esp
764%define %$STK_SAVED_EAX esp + 04h
765%define %$STK_SAVED_GS esp + 08h
766%define %$STK_SAVED_FS esp + 0ch
767%define %$STK_SAVED_ES esp + 10h
768%define %$STK_SAVED_DS esp + 14h
769%define %$ESPOFF 18h
770%define %$STK_VECTOR esp + 00h + %$ESPOFF
771%define %$STK_EIP esp + 04h + %$ESPOFF
772%define %$STK_CS esp + 08h + %$ESPOFF
773%define %$STK_EFLAGS esp + 0ch + %$ESPOFF
774%define %$STK_ESP esp + 10h + %$ESPOFF
775%define %$STK_SS esp + 14h + %$ESPOFF
776%define %$STK_V86_ES esp + 18h + %$ESPOFF
777%define %$STK_V86_DS esp + 1ch + %$ESPOFF
778%define %$STK_V86_FS esp + 20h + %$ESPOFF
779%define %$STK_V86_GS esp + 24h + %$ESPOFF
780
781 mov bx, ss ; load
782 mov ds, bx
783 mov es, bx
784
785 xor bx, bx ; load 0 into gs and fs.
786 mov gs, bx
787 mov fs, bx
788
789 mov eax, cr0 ;; @todo elimitate this read?
790 and eax, ~X86_CR0_WRITE_PROTECT
791 mov cr0, eax
792
793 mov ebx, IMP(g_trpmGuestCtxCore) ; Assume GC as the most common.
794 test byte [%$STK_CS], 3h ; check RPL of the cs selector
795 jnz .save_guest_state
796 test dword [%$STK_EFLAGS], X86_EFL_VM ; If in V86, then guest.
797 jnz .save_guest_state
798 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
799
800 ;
801 ; Save the state.
802 ;
803.save_hyper_state:
804 mov [ebx + CPUMCTXCORE.ecx], ecx
805 lea eax, [%$STK_ESP]
806 mov [ebx + CPUMCTXCORE.esp], eax
807 mov cx, ss
808 mov [ebx + CPUMCTXCORE.ss.Sel], cx
809 jmp .save_state_common
810
811.save_guest_state:
812 mov [ebx + CPUMCTXCORE.ecx], ecx
813 mov eax, [%$STK_ESP]
814 mov [ebx + CPUMCTXCORE.esp], eax
815 mov cx, [%$STK_SS]
816 mov [ebx + CPUMCTXCORE.ss.Sel], cx
817
818.save_state_common:
819 mov eax, [%$STK_SAVED_EAX]
820 mov [ebx + CPUMCTXCORE.eax], eax
821 mov [ebx + CPUMCTXCORE.edx], edx
822 mov eax, [%$STK_SAVED_EBX]
823 mov [ebx + CPUMCTXCORE.ebx], eax
824 mov [ebx + CPUMCTXCORE.esi], esi
825 mov [ebx + CPUMCTXCORE.edi], edi
826 mov [ebx + CPUMCTXCORE.ebp], ebp
827
828 mov cx, [%$STK_CS]
829 mov [ebx + CPUMCTXCORE.cs.Sel], cx
830 mov eax, [%$STK_EIP]
831 mov [ebx + CPUMCTXCORE.eip], eax
832 mov eax, [%$STK_EFLAGS]
833 mov [ebx + CPUMCTXCORE.eflags], eax
834
835%if GC_ARCH_BITS == 64 ; zero out the high dwords - probably not necessary any more.
836 mov dword [ebx + CPUMCTXCORE.eax + 4], 0
837 mov dword [ebx + CPUMCTXCORE.ecx + 4], 0
838 mov dword [ebx + CPUMCTXCORE.edx + 4], 0
839 mov dword [ebx + CPUMCTXCORE.ebx + 4], 0
840 mov dword [ebx + CPUMCTXCORE.esi + 4], 0
841 mov dword [ebx + CPUMCTXCORE.edi + 4], 0
842 mov dword [ebx + CPUMCTXCORE.ebp + 4], 0
843 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
844 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
845%endif
846
847 test dword [%$STK_EFLAGS], X86_EFL_VM
848 jnz .save_V86_segregs
849
850 mov cx, [%$STK_SAVED_ES]
851 mov [ebx + CPUMCTXCORE.es.Sel], cx
852 mov cx, [%$STK_SAVED_DS]
853 mov [ebx + CPUMCTXCORE.ds.Sel], cx
854 mov cx, [%$STK_SAVED_FS]
855 mov [ebx + CPUMCTXCORE.fs.Sel], cx
856 mov cx, [%$STK_SAVED_GS]
857 mov [ebx + CPUMCTXCORE.gs.Sel], cx
858 jmp .done_saving
859
860 ;
861 ; The DS, ES, FS and GS registers are zeroed in V86 mode and their real
862 ; values are on the stack.
863 ;
864.save_V86_segregs:
865 mov cx, [%$STK_V86_ES]
866 mov [ebx + CPUMCTXCORE.es.Sel], cx
867 mov cx, [%$STK_V86_DS]
868 mov [ebx + CPUMCTXCORE.ds.Sel], cx
869 mov cx, [%$STK_V86_FS]
870 mov [ebx + CPUMCTXCORE.fs.Sel], cx
871 mov cx, [%$STK_V86_GS]
872 mov [ebx + CPUMCTXCORE.gs.Sel], cx
873
874.done_saving:
875
876 ;
877 ; Store the information about the active trap/interrupt.
878 ;
879 mov esi, IMP(g_TRPMCPU) ; esi = TRPMCPU until resume!
880 movzx edx, byte [%$STK_VECTOR]
881 mov [esi + TRPMCPU.uActiveVector], edx
882 mov dword [esi + TRPMCPU.uActiveErrorCode], 0
883 mov dword [esi + TRPMCPU.enmActiveType], TRPM_TRAP
884 mov dword [esi + TRPMCPU.uActiveCR2], edx
885%if GC_ARCH_BITS == 64 ; zero out the high dwords.
886 mov dword [esi + TRPMCPU.uActiveErrorCode + 4], 0
887 mov dword [esi + TRPMCPU.uActiveCR2 + 4], 0
888%endif
889
890%ifdef VBOX_WITH_STATISTICS
891 ;
892 ; Update statistics.
893 ;
894 mov edi, IMP(g_TRPM)
895 movzx edx, byte [%$STK_VECTOR] ; vector number
896 imul edx, edx, byte STAMCOUNTER_size
897 add edx, [edi + TRPM.paStatHostIrqRC]
898 STAM_COUNTER_INC edx
899%endif
900
901 ;
902 ; Check if we're in the raw-mode context (RC / hypervisor) when this happened.
903 ;
904 test dword [%$STK_EFLAGS], X86_EFL_VM
905 jnz short .gc_not_raw_mode_context
906
907 test byte [%$STK_CS], 3h ; check RPL of the cs selector
908 jz .rc_in_raw_mode_context
909
910 ;
911 ; Trap in guest code.
912 ;
913.gc_not_raw_mode_context:
914 and dword [ebx + CPUMCTXCORE.eflags], ~X86_EFL_RF ; Clear RF.
915 ; The guest shall not see this in it's state.
916%ifdef DEBUG_STUFF_INT
917 xor eax, eax
918 mov ecx, 'intG' ; indicate trap in GC.
919 movzx edx, byte [%$STK_VECTOR]
920 call trpmDbgDumpRegisterFrame
921%endif
922
923 ;
924 ; Switch back to the host and process it there.
925 ;
926 mov edx, IMP(g_VM)
927 mov eax, VINF_EM_RAW_INTERRUPT
928 call [edx + VM.pfnVMMRCToHostAsm]
929
930 ;
931 ; We've returned!
932 ;
933
934 ; Reset TRPM state
935 xor edx, edx
936 dec edx ; edx = 0ffffffffh
937 xchg [esi + TRPMCPU.uActiveVector], edx
938 mov [esi + TRPMCPU.uPrevVector], edx
939
940%ifdef VBOX_STRICT
941 ; Call CPUM to check sanity.
942 mov edx, IMP(g_VM)
943 push edx
944 call NAME(CPUMRCAssertPreExecutionSanity)
945 add esp, 4
946%endif
947
948 ; For v8086 mode we must branch off before we enable write protection.
949 test dword [ebx + CPUMCTXCORE.eflags], X86_EFL_VM
950 jnz .gc_V86_return
951
952 ; enable WP
953 mov eax, cr0 ;; @todo try elimiate this read.
954 or eax, X86_CR0_WRITE_PROTECT
955 mov cr0, eax
956
957 ; restore guest state and start executing again.
958 mov eax, [ebx + CPUMCTXCORE.eax]
959 mov [%$STK_SAVED_EAX], eax
960 mov ecx, [ebx + CPUMCTXCORE.ecx]
961 mov edx, [ebx + CPUMCTXCORE.edx]
962 mov eax, [ebx + CPUMCTXCORE.ebx]
963 mov [%$STK_SAVED_EBX], eax
964 mov ebp, [ebx + CPUMCTXCORE.ebp]
965 mov esi, [ebx + CPUMCTXCORE.esi]
966 mov edi, [ebx + CPUMCTXCORE.edi]
967
968 mov eax, [ebx + CPUMCTXCORE.esp]
969 mov [%$STK_ESP], eax
970 mov eax, dword [ebx + CPUMCTXCORE.ss.Sel]
971 mov [%$STK_SS], eax
972 mov eax, [ebx + CPUMCTXCORE.eflags]
973 mov [%$STK_EFLAGS], eax
974 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
975 mov [%$STK_CS], eax
976 mov eax, [ebx + CPUMCTXCORE.eip]
977 mov [%$STK_EIP], eax
978
979 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
980 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
981 mov gs, ax
982
983 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
984 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
985 mov fs, ax
986
987 mov ax, [ebx + CPUMCTXCORE.es.Sel]
988 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
989 mov es, ax
990
991 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
992 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
993 mov ds, ax
994
995 ; finally restore our scratch register eax and ebx.
996 pop ebx
997 pop eax
998 add esp, 16 + 4 ; skip segregs, and vector number.
999
1000 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET
1001 iret
1002
1003ALIGNCODE(16)
1004.gc_V86_return:
1005 ;
1006 ; We may be returning to V8086 while having entered from protected mode!
1007 ; So, we have to push the whole stack frame. There's code in CPUMRC that
1008 ; does exactly that, so call it instead of duplicating it.
1009 ;
1010 push ebx
1011 extern NAME(CPUMGCCallV86Code)
1012 call NAME(CPUMGCCallV86Code)
1013 int3 ; doesn't return...
1014
1015
1016 ; -+- Entry point -+-
1017 ;
1018 ; We're in hypervisor mode which means no guest context
1019 ; and special care to be taken to restore the hypervisor
1020 ; context correctly.
1021 ;
1022 ; ATM the only place this can happen is when entering a trap handler.
1023 ; We make ASSUMPTIONS about this in respects to the WP CR0 bit
1024 ;
1025ALIGNCODE(16)
1026.rc_in_raw_mode_context:
1027 ; fix ss:esp.
1028 lea ecx, [%$STK_ESP] ; calc esp at trap
1029 mov [ebx + CPUMCTXCORE.esp], ecx ; update esp in register frame
1030 mov [ebx + CPUMCTXCORE.ss.Sel], ss ; update ss in register frame
1031
1032%ifdef DEBUG_STUFF_INT
1033 xor eax, eax
1034 mov ecx, 'intH' ; indicate trap in RC.
1035 movzx edx, byte [%$STK_VECTOR]
1036 call trpmDbgDumpRegisterFrame
1037%endif
1038
1039 mov edx, IMP(g_VM)
1040 mov eax, VINF_EM_RAW_INTERRUPT_HYPER
1041 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
1042%ifdef DEBUG_STUFF_INT
1043 COM_S_CHAR '!'
1044%endif
1045
1046 ;
1047 ; We've returned!
1048 ; Continue(/Resume/Restart/Whatever) hypervisor execution.
1049 ;
1050
1051 ; Reset TRPM state - don't record this.
1052 ;mov esi, IMP(g_TRPMCPU)
1053 mov dword [esi + TRPMCPU.uActiveVector], 0ffffffffh
1054
1055 ;
1056 ; Restore the hypervisor context and return.
1057 ;
1058 mov eax, [ebx + CPUMCTXCORE.eax]
1059 mov [%$STK_SAVED_EAX], eax
1060 mov ecx, [ebx + CPUMCTXCORE.ecx]
1061 mov edx, [ebx + CPUMCTXCORE.edx]
1062 mov eax, [ebx + CPUMCTXCORE.ebx]
1063 mov [%$STK_SAVED_EBX], eax
1064 mov ebp, [ebx + CPUMCTXCORE.ebp]
1065 mov esi, [ebx + CPUMCTXCORE.esi]
1066 mov edi, [ebx + CPUMCTXCORE.edi]
1067
1068 ; skipping esp & ss.
1069
1070 mov eax, [ebx + CPUMCTXCORE.eflags]
1071 mov [%$STK_EFLAGS], eax
1072 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
1073 mov [%$STK_CS], eax
1074 mov eax, [ebx + CPUMCTXCORE.eip]
1075 mov [%$STK_EIP], eax
1076
1077 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
1078 mov gs, ax
1079
1080 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
1081 mov fs, ax
1082
1083 mov ax, [ebx + CPUMCTXCORE.es.Sel]
1084 mov es, ax
1085
1086 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
1087 mov ds, ax
1088
1089 ; finally restore our scratch register eax and ebx.
1090 pop ebx
1091 pop eax
1092 add esp, 16 + 4 ; skip segregs, and vector number.
1093
1094 iret
1095%pop
1096ENDPROC TRPMGCHandlerInterupt
1097
1098
1099
1100;;
1101; Trap handler for #MC
1102;
1103; This handler will forward the #MC to the host OS. Since this
1104; is generalized in the generic interrupt handler, we just disable
1105; interrupts and push vector number and jump to the generic code.
1106;
1107; Stack:
1108; 10 SS (only if ring transition.)
1109; c ESP (only if ring transition.)
1110; 8 EFLAGS
1111; 4 CS
1112; 0 EIP
1113;
1114; @uses none
1115;
1116ALIGNCODE(16)
1117BEGINPROC_EXPORTED TRPMGCHandlerTrap12
1118 push byte 12h
1119 jmp ti_GenericInterrupt
1120ENDPROC TRPMGCHandlerTrap12
1121
1122
1123
1124
1125;;
1126; Trap handler for double fault (#DF).
1127;
1128; This is a special trap handler executes in separate task with own TSS, with
1129; one of the intermediate memory contexts instead of the shadow context.
1130; The handler will unconditionally print an report to the comport configured
1131; for the COM_S_* macros before attempting to return to the host. If it it ends
1132; up double faulting more than 10 times, it will simply cause an triple fault
1133; to get us out of the mess.
1134;
1135; @param esp Half way down the hypervisor stack + the trap frame.
1136; @param ebp Half way down the hypervisor stack.
1137; @param eflags Interrupts disabled, nested flag is probably set (we don't care).
1138; @param ecx The address of the hypervisor TSS.
1139; @param edi Same as ecx.
1140; @param eax Same as ecx.
1141; @param edx Address of the VM structure.
1142; @param esi Same as edx.
1143; @param ebx Same as edx.
1144; @param ss Hypervisor DS.
1145; @param ds Hypervisor DS.
1146; @param es Hypervisor DS.
1147; @param fs 0
1148; @param gs 0
1149;
1150;
1151; @remark To be able to catch errors with WP turned off, it is required that the
1152; TSS GDT descriptor and the TSSes are writable (X86_PTE_RW). See SELM.cpp
1153; for how to enable this.
1154;
1155; @remark It is *not* safe to resume the VMM after a double fault. (At least not
1156; without clearing the busy flag of the TssTrap8 and fixing whatever cause it.)
1157;
1158ALIGNCODE(16)
1159BEGINPROC_EXPORTED TRPMGCHandlerTrap08
1160 ; be careful.
1161 cli
1162 cld
1163
1164 ;
1165 ; Disable write protection.
1166 ;
1167 mov eax, cr0
1168 and eax, ~X86_CR0_WRITE_PROTECT
1169 mov cr0, eax
1170
1171 ;
1172 ; Load Hypervisor DS and ES (get it from the SS) - paranoia, but the TSS could be overwritten.. :)
1173 ;
1174 mov eax, ss
1175 mov ds, eax
1176 mov es, eax
1177
1178 COM_S_PRINT 10,13,'*** Guru Meditation 00000008 - Double Fault! ***',10,13
1179
1180 COM_S_PRINT 'VM='
1181 COM_S_DWORD_REG edx
1182 COM_S_PRINT ' prevTSS='
1183 COM_S_DWORD_REG ecx
1184 COM_S_PRINT ' prevCR3='
1185 mov eax, [ecx + VBOXTSS.cr3]
1186 COM_S_DWORD_REG eax
1187 COM_S_PRINT ' prevLdtr='
1188 movzx eax, word [ecx + VBOXTSS.selLdt]
1189 COM_S_DWORD_REG eax
1190 COM_S_NEWLINE
1191
1192 ;
1193 ; Create CPUMCTXCORE structure.
1194 ;
1195 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
1196
1197 mov eax, [ecx + VBOXTSS.eip]
1198 mov [ebx + CPUMCTXCORE.eip], eax
1199%if GC_ARCH_BITS == 64
1200 ; zero out the high dword
1201 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
1202%endif
1203 mov eax, [ecx + VBOXTSS.eflags]
1204 mov [ebx + CPUMCTXCORE.eflags], eax
1205
1206 movzx eax, word [ecx + VBOXTSS.cs]
1207 mov dword [ebx + CPUMCTXCORE.cs.Sel], eax
1208 movzx eax, word [ecx + VBOXTSS.ds]
1209 mov dword [ebx + CPUMCTXCORE.ds.Sel], eax
1210 movzx eax, word [ecx + VBOXTSS.es]
1211 mov dword [ebx + CPUMCTXCORE.es.Sel], eax
1212 movzx eax, word [ecx + VBOXTSS.fs]
1213 mov dword [ebx + CPUMCTXCORE.fs.Sel], eax
1214 movzx eax, word [ecx + VBOXTSS.gs]
1215 mov dword [ebx + CPUMCTXCORE.gs.Sel], eax
1216 movzx eax, word [ecx + VBOXTSS.ss]
1217 mov [ebx + CPUMCTXCORE.ss.Sel], eax
1218 mov eax, [ecx + VBOXTSS.esp]
1219 mov [ebx + CPUMCTXCORE.esp], eax
1220%if GC_ARCH_BITS == 64
1221 ; zero out the high dword
1222 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
1223%endif
1224 mov eax, [ecx + VBOXTSS.ecx]
1225 mov [ebx + CPUMCTXCORE.ecx], eax
1226 mov eax, [ecx + VBOXTSS.edx]
1227 mov [ebx + CPUMCTXCORE.edx], eax
1228 mov eax, [ecx + VBOXTSS.ebx]
1229 mov [ebx + CPUMCTXCORE.ebx], eax
1230 mov eax, [ecx + VBOXTSS.eax]
1231 mov [ebx + CPUMCTXCORE.eax], eax
1232 mov eax, [ecx + VBOXTSS.ebp]
1233 mov [ebx + CPUMCTXCORE.ebp], eax
1234 mov eax, [ecx + VBOXTSS.esi]
1235 mov [ebx + CPUMCTXCORE.esi], eax
1236 mov eax, [ecx + VBOXTSS.edi]
1237 mov [ebx + CPUMCTXCORE.edi], eax
1238
1239 ;
1240 ; Show regs
1241 ;
1242 mov eax, 0ffffffffh
1243 mov ecx, 'trpH' ; indicate trap.
1244 mov edx, 08h ; vector number
1245 call trpmDbgDumpRegisterFrame
1246
1247 ;
1248 ; Should we try go back?
1249 ;
1250 inc dword [df_Count]
1251 cmp dword [df_Count], byte 10
1252 jb df_to_host
1253 jmp df_tripple_fault
1254df_Count: dd 0
1255
1256 ;
1257 ; Try return to the host.
1258 ;
1259df_to_host:
1260 COM_S_PRINT 'Trying to return to host...',10,13
1261 mov edx, IMP(g_VM)
1262 mov eax, VERR_TRPM_PANIC
1263 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
1264 jmp short df_to_host
1265
1266 ;
1267 ; Perform a tripple fault.
1268 ;
1269df_tripple_fault:
1270 COM_S_PRINT 'Giving up - tripple faulting the machine...',10,13
1271 push byte 0
1272 push byte 0
1273 sidt [esp]
1274 mov word [esp], 0
1275 lidt [esp]
1276 xor eax, eax
1277 mov dword [eax], 0
1278 jmp df_tripple_fault
1279
1280ENDPROC TRPMGCHandlerTrap08
1281
1282
1283
1284
1285;;
1286; Internal procedure used to dump registers.
1287;
1288; @param ebx Pointer to CPUMCTXCORE.
1289; @param edx Vector number
1290; @param ecx 'trap' if trap, 'int' if interrupt.
1291; @param eax Error code if trap.
1292;
1293trpmDbgDumpRegisterFrame:
1294 sub esp, byte 8 ; working space for sidt/sgdt/etc
1295
1296; Init _must_ be done on host before crashing!
1297; push edx
1298; push eax
1299; COM_INIT
1300; pop eax
1301; pop edx
1302
1303 cmp ecx, 'trpH'
1304 je near tddrf_trpH
1305 cmp ecx, 'trpG'
1306 je near tddrf_trpG
1307 cmp ecx, 'intH'
1308 je near tddrf_intH
1309 cmp ecx, 'intG'
1310 je near tddrf_intG
1311 cmp ecx, 'resH'
1312 je near tddrf_resH
1313 COM_S_PRINT 10,13,'*** Bogus Dump Code '
1314 jmp tddrf_regs
1315
1316%if 1 ; the verbose version
1317
1318tddrf_intG:
1319 COM_S_PRINT 10,13,'*** Interrupt (Guest) '
1320 COM_S_DWORD_REG edx
1321 jmp tddrf_regs
1322
1323tddrf_intH:
1324 COM_S_PRINT 10,13,'*** Interrupt (Hypervisor) '
1325 COM_S_DWORD_REG edx
1326 jmp tddrf_regs
1327
1328tddrf_trpG:
1329 COM_S_PRINT 10,13,'*** Trap '
1330 jmp tddrf_trap_rest
1331
1332%else ; the short version
1333
1334tddrf_intG:
1335 COM_S_CHAR 'I'
1336 jmp tddrf_ret
1337
1338tddrf_intH:
1339 COM_S_CHAR 'i'
1340 jmp tddrf_ret
1341
1342tddrf_trpG:
1343 COM_S_CHAR 'T'
1344 jmp tddrf_ret
1345
1346%endif ; the short version
1347
1348tddrf_trpH:
1349 COM_S_PRINT 10,13,'*** Guru Meditation '
1350 jmp tddrf_trap_rest
1351
1352tddrf_resH:
1353 COM_S_PRINT 10,13,'*** Resuming Hypervisor Trap '
1354 jmp tddrf_trap_rest
1355
1356tddrf_trap_rest:
1357 COM_S_DWORD_REG edx
1358 COM_S_PRINT ' ErrorCode='
1359 COM_S_DWORD_REG eax
1360 COM_S_PRINT ' cr2='
1361 mov ecx, cr2
1362 COM_S_DWORD_REG ecx
1363
1364tddrf_regs:
1365 COM_S_PRINT ' ***',10,13,'cs:eip='
1366 movzx ecx, word [ebx + CPUMCTXCORE.cs.Sel]
1367 COM_S_DWORD_REG ecx
1368 COM_S_CHAR ':'
1369 mov ecx, [ebx + CPUMCTXCORE.eip]
1370 COM_S_DWORD_REG ecx
1371
1372 COM_S_PRINT ' ss:esp='
1373 movzx ecx, word [ebx + CPUMCTXCORE.ss.Sel]
1374 COM_S_DWORD_REG ecx
1375 COM_S_CHAR ':'
1376 mov ecx, [ebx + CPUMCTXCORE.esp]
1377 COM_S_DWORD_REG ecx
1378
1379
1380 sgdt [esp]
1381 COM_S_PRINT 10,13,' gdtr='
1382 movzx ecx, word [esp]
1383 COM_S_DWORD_REG ecx
1384 COM_S_CHAR ':'
1385 mov ecx, [esp + 2]
1386 COM_S_DWORD_REG ecx
1387
1388 sidt [esp]
1389 COM_S_PRINT ' idtr='
1390 movzx ecx, word [esp]
1391 COM_S_DWORD_REG ecx
1392 COM_S_CHAR ':'
1393 mov ecx, [esp + 2]
1394 COM_S_DWORD_REG ecx
1395
1396
1397 str [esp] ; yasm BUG! it generates sldt [esp] here! YASMCHECK!
1398 COM_S_PRINT 10,13,' tr='
1399 movzx ecx, word [esp]
1400 COM_S_DWORD_REG ecx
1401
1402 sldt [esp]
1403 COM_S_PRINT ' ldtr='
1404 movzx ecx, word [esp]
1405 COM_S_DWORD_REG ecx
1406
1407 COM_S_PRINT ' eflags='
1408 mov ecx, [ebx + CPUMCTXCORE.eflags]
1409 COM_S_DWORD_REG ecx
1410
1411
1412 COM_S_PRINT 10,13,'cr0='
1413 mov ecx, cr0
1414 COM_S_DWORD_REG ecx
1415
1416 COM_S_PRINT ' cr2='
1417 mov ecx, cr2
1418 COM_S_DWORD_REG ecx
1419
1420 COM_S_PRINT ' cr3='
1421 mov ecx, cr3
1422 COM_S_DWORD_REG ecx
1423 COM_S_PRINT ' cr4='
1424 mov ecx, cr4
1425 COM_S_DWORD_REG ecx
1426
1427
1428 COM_S_PRINT 10,13,' ds='
1429 movzx ecx, word [ebx + CPUMCTXCORE.ds.Sel]
1430 COM_S_DWORD_REG ecx
1431
1432 COM_S_PRINT ' es='
1433 movzx ecx, word [ebx + CPUMCTXCORE.es.Sel]
1434 COM_S_DWORD_REG ecx
1435
1436 COM_S_PRINT ' fs='
1437 movzx ecx, word [ebx + CPUMCTXCORE.fs.Sel]
1438 COM_S_DWORD_REG ecx
1439
1440 COM_S_PRINT ' gs='
1441 movzx ecx, word [ebx + CPUMCTXCORE.gs.Sel]
1442 COM_S_DWORD_REG ecx
1443
1444
1445 COM_S_PRINT 10,13,'eax='
1446 mov ecx, [ebx + CPUMCTXCORE.eax]
1447 COM_S_DWORD_REG ecx
1448
1449 COM_S_PRINT ' ebx='
1450 mov ecx, [ebx + CPUMCTXCORE.ebx]
1451 COM_S_DWORD_REG ecx
1452
1453 COM_S_PRINT ' ecx='
1454 mov ecx, [ebx + CPUMCTXCORE.ecx]
1455 COM_S_DWORD_REG ecx
1456
1457 COM_S_PRINT ' edx='
1458 mov ecx, [ebx + CPUMCTXCORE.edx]
1459 COM_S_DWORD_REG ecx
1460
1461
1462 COM_S_PRINT 10,13,'esi='
1463 mov ecx, [ebx + CPUMCTXCORE.esi]
1464 COM_S_DWORD_REG ecx
1465
1466 COM_S_PRINT ' edi='
1467 mov ecx, [ebx + CPUMCTXCORE.edi]
1468 COM_S_DWORD_REG ecx
1469
1470 COM_S_PRINT ' ebp='
1471 mov ecx, [ebx + CPUMCTXCORE.ebp]
1472 COM_S_DWORD_REG ecx
1473
1474
1475 COM_S_NEWLINE
1476
1477tddrf_ret:
1478 add esp, byte 8
1479 ret
1480
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