VirtualBox

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

Last change on this file since 46177 was 42771, checked in by vboxsync, 12 years ago

TRPM,CPUM: Added sanity assertions before resuming guest execution.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 46.6 KB
Line 
1; $Id: TRPMRCHandlersA.asm 42771 2012-08-11 20:15:47Z vboxsync $
2;; @file
3; TRPM - Raw-mode Context Trap Handlers
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;*******************************************************************************
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 ;; @todo check this for conforming segments.
300 jnz .save_state
301 test dword [%$STK_EFLAGS], X86_EFL_VM; If in V86, then guest.
302 jnz .save_state
303 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
304
305 ;
306 ; Save the state.
307 ;
308 ; ASSUMPTION: If trap in hypervisor, we assume that we can read two dword
309 ; under the bottom of the stack. This is atm safe.
310 ;
311.save_state:
312 mov eax, [%$STK_SAVED_EAX]
313 mov [ebx + CPUMCTXCORE.eax], eax
314 mov [ebx + CPUMCTXCORE.ecx], ecx
315 mov [ebx + CPUMCTXCORE.edx], edx
316 mov eax, [%$STK_SAVED_EBX]
317 mov [ebx + CPUMCTXCORE.ebx], eax
318 mov [ebx + CPUMCTXCORE.esi], esi
319 mov [ebx + CPUMCTXCORE.edi], edi
320 mov [ebx + CPUMCTXCORE.ebp], ebp
321
322 mov eax, [%$STK_ESP]
323 mov [ebx + CPUMCTXCORE.esp], eax
324 mov cx, [%$STK_SS]
325 mov [ebx + CPUMCTXCORE.ss.Sel], cx
326
327 mov cx, [%$STK_CS]
328 mov [ebx + CPUMCTXCORE.cs.Sel], cx
329 mov eax, [%$STK_EIP]
330 mov [ebx + CPUMCTXCORE.eip], eax
331 mov eax, [%$STK_EFLAGS]
332 mov [ebx + CPUMCTXCORE.eflags], eax
333
334%if GC_ARCH_BITS == 64 ; zero out the high dwords - probably not necessary any more.
335 mov dword [ebx + CPUMCTXCORE.eax + 4], 0
336 mov dword [ebx + CPUMCTXCORE.ecx + 4], 0
337 mov dword [ebx + CPUMCTXCORE.edx + 4], 0
338 mov dword [ebx + CPUMCTXCORE.ebx + 4], 0
339 mov dword [ebx + CPUMCTXCORE.esi + 4], 0
340 mov dword [ebx + CPUMCTXCORE.edi + 4], 0
341 mov dword [ebx + CPUMCTXCORE.ebp + 4], 0
342 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
343 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
344%endif
345
346 test dword [%$STK_EFLAGS], X86_EFL_VM
347 jnz .save_V86_segregs
348
349 mov cx, [%$STK_SAVED_ES]
350 mov [ebx + CPUMCTXCORE.es.Sel], cx
351 mov cx, [%$STK_SAVED_DS]
352 mov [ebx + CPUMCTXCORE.ds.Sel], cx
353 mov cx, [%$STK_SAVED_FS]
354 mov [ebx + CPUMCTXCORE.fs.Sel], cx
355 mov cx, [%$STK_SAVED_GS]
356 mov [ebx + CPUMCTXCORE.gs.Sel], cx
357 jmp .done_saving
358
359 ;
360 ; The DS, ES, FS and GS registers are zeroed in V86 mode and their real
361 ; values are on the stack.
362 ;
363.save_V86_segregs:
364 mov cx, [%$STK_V86_ES]
365 mov [ebx + CPUMCTXCORE.es.Sel], cx
366 mov cx, [%$STK_V86_DS]
367 mov [ebx + CPUMCTXCORE.ds.Sel], cx
368 mov cx, [%$STK_V86_FS]
369 mov [ebx + CPUMCTXCORE.fs.Sel], cx
370 mov cx, [%$STK_V86_GS]
371 mov [ebx + CPUMCTXCORE.gs.Sel], cx
372
373.done_saving:
374
375%ifdef VBOX_WITH_STATISTICS
376 ;
377 ; Start profiling.
378 ;
379 mov edx, [%$STK_VECTOR]
380 imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128.
381 add edx, TRPM.aStatGCTraps
382 add edx, IMP(g_TRPM)
383 STAM_PROFILE_ADV_START edx
384%endif
385
386 ;
387 ; Store the information about the active trap/interrupt.
388 ;
389 mov esi, IMP(g_TRPMCPU) ; esi = TRPMCPU until resume!
390 movzx edx, byte [%$STK_VECTOR]
391 mov [esi + TRPMCPU.uActiveVector], edx
392 mov edx, [%$STK_ERRCD]
393 mov [esi + TRPMCPU.uActiveErrorCode], edx
394 mov dword [esi + TRPMCPU.enmActiveType], TRPM_TRAP
395 mov edx, cr2 ;; @todo Check how expensive cr2 reads are!
396 mov dword [esi + TRPMCPU.uActiveCR2], edx
397%if GC_ARCH_BITS == 64 ; zero out the high dwords.
398 mov dword [esi + TRPMCPU.uActiveErrorCode + 4], 0
399 mov dword [esi + TRPMCPU.uActiveCR2 + 4], 0
400%endif
401
402 ;
403 ; Check if we're in the raw-mode context (RC / hypervisor) when this happened.
404 ;
405 test dword [%$STK_EFLAGS], X86_EFL_VM
406 jnz short .gc_not_raw_mode_context
407
408 test byte [%$STK_CS], 3h ; check RPL of the cs selector
409 jz .rc_in_raw_mode_context
410
411 ;
412 ; Trap in guest code.
413 ;
414.gc_not_raw_mode_context:
415%ifdef DEBUG_STUFF_TRPG
416 mov eax, [%$STK_ERRCD]
417 mov ecx, 'trpG' ; indicate trap.
418 mov edx, [%$STK_VECTOR]
419 call trpmDbgDumpRegisterFrame
420%endif
421
422 ;
423 ; Do we have a GC handler for these traps?
424 ;
425 mov edx, [%$STK_VECTOR]
426 mov eax, [g_apfnStaticTrapHandlersGuest + edx * 4]
427 or eax, eax
428 jnz short .gc_have_static_handler
429 mov eax, VINF_EM_RAW_GUEST_TRAP
430 jmp short .gc_guest_trap
431
432 ;
433 ; Call static handler.
434 ;
435.gc_have_static_handler:
436 push ebx ; Param 2 - CPUMCTXCORE pointer.
437 push esi ; Param 1 - Pointer to TRPMCPU.
438 call eax
439 add esp, byte 8 ; cleanup stack (cdecl)
440 or eax, eax
441 je near .gc_continue_guest
442
443 ;
444 ; Switch back to the host and process it there.
445 ;
446.gc_guest_trap:
447%ifdef VBOX_WITH_STATISTICS
448 mov edx, [%$STK_VECTOR]
449 imul edx, edx, byte STAMPROFILEADV_size ; assume < 128
450 add edx, IMP(g_TRPM)
451 add edx, TRPM.aStatGCTraps
452 STAM_PROFILE_ADV_STOP edx
453%endif
454 mov edx, IMP(g_VM)
455 call [edx + VM.pfnVMMRCToHostAsm]
456
457 ; We shouldn't ever return this way. So, raise a special IPE if we do.
458.gc_panic_again:
459 mov eax, VERR_TRPM_IPE_3
460 mov edx, IMP(g_VM)
461 call [edx + VM.pfnVMMRCToHostAsm]
462 jmp .gc_panic_again
463
464 ;
465 ; Continue(/Resume/Restart/Whatever) guest execution.
466 ;
467ALIGNCODE(16)
468.gc_continue_guest:
469%ifdef VBOX_WITH_STATISTICS
470 mov edx, [%$STK_VECTOR]
471 imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128
472 add edx, TRPM.aStatGCTraps
473 add edx, IMP(g_TRPM)
474 STAM_PROFILE_ADV_STOP edx
475%endif
476
477%ifdef VBOX_STRICT
478 ; Call CPUM to check sanity.
479 mov edx, IMP(g_VM)
480 push edx
481 call NAME(CPUMRCAssertPreExecutionSanity)
482 add esp, 4
483%endif
484
485 ; enable WP
486 mov eax, cr0 ;; @todo try elimiate this read.
487 or eax, X86_CR0_WRITE_PROTECT
488 mov cr0, eax
489
490 ; restore guest state and start executing again.
491 mov eax, [ebx + CPUMCTXCORE.eax]
492 mov [%$STK_SAVED_EAX], eax
493 mov ecx, [ebx + CPUMCTXCORE.ecx]
494 mov edx, [ebx + CPUMCTXCORE.edx]
495 mov eax, [ebx + CPUMCTXCORE.ebx]
496 mov [%$STK_SAVED_EBX], eax
497 mov ebp, [ebx + CPUMCTXCORE.ebp]
498 mov esi, [ebx + CPUMCTXCORE.esi]
499 mov edi, [ebx + CPUMCTXCORE.edi]
500
501 mov eax, [ebx + CPUMCTXCORE.esp]
502 mov [%$STK_ESP], eax
503 mov eax, dword [ebx + CPUMCTXCORE.ss.Sel]
504 mov [%$STK_SS], eax
505 mov eax, [ebx + CPUMCTXCORE.eflags]
506 mov [%$STK_EFLAGS], eax
507 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
508 mov [%$STK_CS], eax
509 mov eax, [ebx + CPUMCTXCORE.eip]
510 mov [%$STK_EIP], eax
511
512 test dword [ebx + CPUMCTXCORE.eflags], X86_EFL_VM
513 jnz .gc_V86_return
514
515 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
516 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
517 mov gs, ax
518
519 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
520 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
521 mov fs, ax
522
523 mov ax, [ebx + CPUMCTXCORE.es.Sel]
524 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
525 mov es, ax
526
527 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
528 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
529 mov ds, ax
530
531 ; finally restore our scratch register eax and ebx.
532 pop ebx
533 pop eax
534 add esp, 16 + 8 ; skip segregs, error code, and vector number.
535
536 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET
537 iret
538
539ALIGNCODE(16)
540.gc_V86_return:
541 mov eax, dword [ebx + CPUMCTXCORE.es.Sel]
542 mov [%$STK_V86_ES], eax
543 mov eax, dword [ebx + CPUMCTXCORE.ds.Sel]
544 mov [%$STK_V86_DS], eax
545 mov eax, dword [ebx + CPUMCTXCORE.fs.Sel]
546 mov [%$STK_V86_FS], eax
547 mov eax, dword [ebx + CPUMCTXCORE.gs.Sel]
548 mov [%$STK_V86_GS], eax
549
550 ; finally restore our scratch register eax and ebx.
551 pop ebx
552 pop eax
553 add esp, 16 + 8 ; skip segregs, error code, and vector number.
554
555 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86
556 iret
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 ;; @todo check this for conforming segments.
796 jnz .save_state
797 test dword [%$STK_EFLAGS], X86_EFL_VM ; If in V86, then guest.
798 jnz .save_state
799 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
800
801 ;
802 ; Save the state.
803 ;
804 ; ASSUMPTION: If trap in hypervisor, we assume that we can read two dword
805 ; under the bottom of the stack. This is atm safe.
806 ;
807.save_state:
808 mov eax, [%$STK_SAVED_EAX]
809 mov [ebx + CPUMCTXCORE.eax], eax
810 mov [ebx + CPUMCTXCORE.ecx], ecx
811 mov [ebx + CPUMCTXCORE.edx], edx
812 mov eax, [%$STK_SAVED_EBX]
813 mov [ebx + CPUMCTXCORE.ebx], eax
814 mov [ebx + CPUMCTXCORE.esi], esi
815 mov [ebx + CPUMCTXCORE.edi], edi
816 mov [ebx + CPUMCTXCORE.ebp], ebp
817
818 mov eax, [%$STK_ESP]
819 mov [ebx + CPUMCTXCORE.esp], eax
820 mov cx, [%$STK_SS]
821 mov [ebx + CPUMCTXCORE.ss.Sel], cx
822
823 mov cx, [%$STK_CS]
824 mov [ebx + CPUMCTXCORE.cs.Sel], cx
825 mov eax, [%$STK_EIP]
826 mov [ebx + CPUMCTXCORE.eip], eax
827 mov eax, [%$STK_EFLAGS]
828 mov [ebx + CPUMCTXCORE.eflags], eax
829
830%if GC_ARCH_BITS == 64 ; zero out the high dwords - probably not necessary any more.
831 mov dword [ebx + CPUMCTXCORE.eax + 4], 0
832 mov dword [ebx + CPUMCTXCORE.ecx + 4], 0
833 mov dword [ebx + CPUMCTXCORE.edx + 4], 0
834 mov dword [ebx + CPUMCTXCORE.ebx + 4], 0
835 mov dword [ebx + CPUMCTXCORE.esi + 4], 0
836 mov dword [ebx + CPUMCTXCORE.edi + 4], 0
837 mov dword [ebx + CPUMCTXCORE.ebp + 4], 0
838 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
839 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
840%endif
841
842 test dword [%$STK_EFLAGS], X86_EFL_VM
843 jnz .save_V86_segregs
844
845 mov cx, [%$STK_SAVED_ES]
846 mov [ebx + CPUMCTXCORE.es.Sel], cx
847 mov cx, [%$STK_SAVED_DS]
848 mov [ebx + CPUMCTXCORE.ds.Sel], cx
849 mov cx, [%$STK_SAVED_FS]
850 mov [ebx + CPUMCTXCORE.fs.Sel], cx
851 mov cx, [%$STK_SAVED_GS]
852 mov [ebx + CPUMCTXCORE.gs.Sel], cx
853 jmp .done_saving
854
855 ;
856 ; The DS, ES, FS and GS registers are zeroed in V86 mode and their real
857 ; values are on the stack.
858 ;
859.save_V86_segregs:
860 mov cx, [%$STK_V86_ES]
861 mov [ebx + CPUMCTXCORE.es.Sel], cx
862 mov cx, [%$STK_V86_DS]
863 mov [ebx + CPUMCTXCORE.ds.Sel], cx
864 mov cx, [%$STK_V86_FS]
865 mov [ebx + CPUMCTXCORE.fs.Sel], cx
866 mov cx, [%$STK_V86_GS]
867 mov [ebx + CPUMCTXCORE.gs.Sel], cx
868
869.done_saving:
870
871 ;
872 ; Store the information about the active trap/interrupt.
873 ;
874 mov esi, IMP(g_TRPMCPU) ; esi = TRPMCPU until resume!
875 movzx edx, byte [%$STK_VECTOR]
876 mov [esi + TRPMCPU.uActiveVector], edx
877 mov dword [esi + TRPMCPU.uActiveErrorCode], 0
878 mov dword [esi + TRPMCPU.enmActiveType], TRPM_TRAP
879 mov dword [esi + TRPMCPU.uActiveCR2], edx
880%if GC_ARCH_BITS == 64 ; zero out the high dwords.
881 mov dword [esi + TRPMCPU.uActiveErrorCode + 4], 0
882 mov dword [esi + TRPMCPU.uActiveCR2 + 4], 0
883%endif
884
885%ifdef VBOX_WITH_STATISTICS
886 ;
887 ; Update statistics.
888 ;
889 mov edi, IMP(g_TRPM)
890 movzx edx, byte [%$STK_VECTOR] ; vector number
891 imul edx, edx, byte STAMCOUNTER_size
892 add edx, [edi + TRPM.paStatHostIrqRC]
893 STAM_COUNTER_INC edx
894%endif
895
896 ;
897 ; Check if we're in the raw-mode context (RC / hypervisor) when this happened.
898 ;
899 test dword [%$STK_EFLAGS], X86_EFL_VM
900 jnz short .gc_not_raw_mode_context
901
902 test byte [%$STK_CS], 3h ; check RPL of the cs selector
903 jz .rc_in_raw_mode_context
904
905 ;
906 ; Trap in guest code.
907 ;
908.gc_not_raw_mode_context:
909 and dword [ebx + CPUMCTXCORE.eflags], ~X86_EFL_RF ; Clear RF.
910 ; The guest shall not see this in it's state.
911%ifdef DEBUG_STUFF_INT
912 xor eax, eax
913 mov ecx, 'intG' ; indicate trap in GC.
914 movzx edx, byte [%$STK_VECTOR]
915 call trpmDbgDumpRegisterFrame
916%endif
917
918 ;
919 ; Switch back to the host and process it there.
920 ;
921 mov edx, IMP(g_VM)
922 mov eax, VINF_EM_RAW_INTERRUPT
923 call [edx + VM.pfnVMMRCToHostAsm]
924
925 ;
926 ; We've returned!
927 ;
928
929 ; Reset TRPM state
930 xor edx, edx
931 dec edx ; edx = 0ffffffffh
932 xchg [esi + TRPMCPU.uActiveVector], edx
933 mov [esi + TRPMCPU.uPrevVector], edx
934
935%ifdef VBOX_STRICT
936 ; Call CPUM to check sanity.
937 mov edx, IMP(g_VM)
938 push edx
939 call NAME(CPUMRCAssertPreExecutionSanity)
940 add esp, 4
941%endif
942
943 ; enable WP
944 mov eax, cr0 ;; @todo try elimiate this read.
945 or eax, X86_CR0_WRITE_PROTECT
946 mov cr0, eax
947
948 ; restore guest state and start executing again.
949 mov eax, [ebx + CPUMCTXCORE.eax]
950 mov [%$STK_SAVED_EAX], eax
951 mov ecx, [ebx + CPUMCTXCORE.ecx]
952 mov edx, [ebx + CPUMCTXCORE.edx]
953 mov eax, [ebx + CPUMCTXCORE.ebx]
954 mov [%$STK_SAVED_EBX], eax
955 mov ebp, [ebx + CPUMCTXCORE.ebp]
956 mov esi, [ebx + CPUMCTXCORE.esi]
957 mov edi, [ebx + CPUMCTXCORE.edi]
958
959 mov eax, [ebx + CPUMCTXCORE.esp]
960 mov [%$STK_ESP], eax
961 mov eax, dword [ebx + CPUMCTXCORE.ss.Sel]
962 mov [%$STK_SS], eax
963 mov eax, [ebx + CPUMCTXCORE.eflags]
964 mov [%$STK_EFLAGS], eax
965 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
966 mov [%$STK_CS], eax
967 mov eax, [ebx + CPUMCTXCORE.eip]
968 mov [%$STK_EIP], eax
969
970 test dword [ebx + CPUMCTXCORE.eflags], X86_EFL_VM
971 jnz .gc_V86_return
972
973 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
974 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
975 mov gs, ax
976
977 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
978 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
979 mov fs, ax
980
981 mov ax, [ebx + CPUMCTXCORE.es.Sel]
982 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
983 mov es, ax
984
985 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
986 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
987 mov ds, ax
988
989 ; finally restore our scratch register eax and ebx.
990 pop ebx
991 pop eax
992 add esp, 16 + 4 ; skip segregs, and vector number.
993
994 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET
995 iret
996
997ALIGNCODE(16)
998.gc_V86_return:
999 mov eax, dword [ebx + CPUMCTXCORE.es.Sel]
1000 mov [%$STK_V86_ES], eax
1001 mov eax, dword [ebx + CPUMCTXCORE.ds.Sel]
1002 mov [%$STK_V86_DS], eax
1003 mov eax, dword [ebx + CPUMCTXCORE.fs.Sel]
1004 mov [%$STK_V86_FS], eax
1005 mov eax, dword [ebx + CPUMCTXCORE.gs.Sel]
1006 mov [%$STK_V86_GS], eax
1007
1008 ; finally restore our scratch register eax and ebx.
1009 pop ebx
1010 pop eax
1011 add esp, 16 + 4 ; skip segregs, and vector number.
1012
1013 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86
1014 iret
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