VirtualBox

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

Last change on this file since 41939 was 41931, checked in by vboxsync, 12 years ago

TRPM: Save state directly to the CPUMCPU context member instead of putting on the stack. this avoid copying the state around before returning to host context to service an IRQ, or before using IEM.

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