VirtualBox

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

Last change on this file since 47690 was 47690, checked in by vboxsync, 11 years ago

TRPM: Don't underflow the stack when trapping in the world switcher.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 46.8 KB
Line 
1; $Id: TRPMRCHandlersA.asm 47690 2013-08-13 12:53:48Z 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 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 ; enable WP
491 mov eax, cr0 ;; @todo try elimiate this read.
492 or eax, X86_CR0_WRITE_PROTECT
493 mov cr0, eax
494
495 ; restore guest state and start executing again.
496 mov eax, [ebx + CPUMCTXCORE.eax]
497 mov [%$STK_SAVED_EAX], eax
498 mov ecx, [ebx + CPUMCTXCORE.ecx]
499 mov edx, [ebx + CPUMCTXCORE.edx]
500 mov eax, [ebx + CPUMCTXCORE.ebx]
501 mov [%$STK_SAVED_EBX], eax
502 mov ebp, [ebx + CPUMCTXCORE.ebp]
503 mov esi, [ebx + CPUMCTXCORE.esi]
504 mov edi, [ebx + CPUMCTXCORE.edi]
505
506 mov eax, [ebx + CPUMCTXCORE.esp]
507 mov [%$STK_ESP], eax
508 mov eax, dword [ebx + CPUMCTXCORE.ss.Sel]
509 mov [%$STK_SS], eax
510 mov eax, [ebx + CPUMCTXCORE.eflags]
511 mov [%$STK_EFLAGS], eax
512 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
513 mov [%$STK_CS], eax
514 mov eax, [ebx + CPUMCTXCORE.eip]
515 mov [%$STK_EIP], eax
516
517 test dword [ebx + CPUMCTXCORE.eflags], X86_EFL_VM
518 jnz .gc_V86_return
519
520 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
521 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
522 mov gs, ax
523
524 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
525 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
526 mov fs, ax
527
528 mov ax, [ebx + CPUMCTXCORE.es.Sel]
529 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
530 mov es, ax
531
532 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
533 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
534 mov ds, ax
535
536 ; finally restore our scratch register eax and ebx.
537 pop ebx
538 pop eax
539 add esp, 16 + 8 ; skip segregs, error code, and vector number.
540
541 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET
542 iret
543
544ALIGNCODE(16)
545.gc_V86_return:
546 mov eax, dword [ebx + CPUMCTXCORE.es.Sel]
547 mov [%$STK_V86_ES], eax
548 mov eax, dword [ebx + CPUMCTXCORE.ds.Sel]
549 mov [%$STK_V86_DS], eax
550 mov eax, dword [ebx + CPUMCTXCORE.fs.Sel]
551 mov [%$STK_V86_FS], eax
552 mov eax, dword [ebx + CPUMCTXCORE.gs.Sel]
553 mov [%$STK_V86_GS], eax
554
555 ; finally restore our scratch register eax and ebx.
556 pop ebx
557 pop eax
558 add esp, 16 + 8 ; skip segregs, error code, and vector number.
559
560 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86
561 iret
562
563 ;
564 ; Trap in Hypervisor, try to handle it.
565 ;
566 ; (eax = pTRPMCPU)
567 ;
568ALIGNCODE(16)
569.rc_in_raw_mode_context:
570 ; fix ss:esp.
571 lea ecx, [%$STK_ESP] ; calc esp at trap
572 mov [ebx + CPUMCTXCORE.esp], ecx; update esp in register frame
573 mov [ebx + CPUMCTXCORE.ss.Sel], ss ; update ss in register frame
574
575 ; check for temporary handler.
576 movzx edx, byte [esi + TRPMCPU.uActiveVector]
577 mov edi, IMP(g_TRPM)
578 xor ecx, ecx
579 xchg ecx, [edi + TRPM.aTmpTrapHandlers + edx * 4] ; ecx = Temp handler pointer or 0
580 or ecx, ecx
581 jnz short .rc_have_temporary_handler
582
583 ; check for static trap handler.
584 mov ecx, [g_apfnStaticTrapHandlersHyper + edx * 4] ; ecx = Static handler pointer or 0
585 or ecx, ecx
586 jnz short .rc_have_static_handler
587 jmp .rc_abandon_ship
588
589
590 ;
591 ; Temporary trap handler present, call it (CDECL).
592 ;
593.rc_have_temporary_handler:
594 push ebx ; Param 2 - Pointer to CPUMCTXCORE.
595 push IMP(g_VM) ; Param 1 - Pointer to VM.
596 call ecx
597 add esp, byte 8 ; cleanup stack (cdecl)
598
599 cmp eax, byte VINF_SUCCESS ; If completely handled Then resume execution.
600 je near .rc_continue
601 jmp .rc_abandon_ship
602
603
604 ;
605 ; Static trap handler present, call it (CDECL).
606 ;
607.rc_have_static_handler:
608 push ebx ; Param 2 - Pointer to CPUMCTXCORE.
609 push esi ; Param 1 - Pointer to TRPMCPU
610 call ecx
611 add esp, byte 8 ; cleanup stack (cdecl)
612
613 cmp eax, byte VINF_SUCCESS ; If completely handled Then resume execution.
614 je short .rc_continue
615 cmp eax, VINF_EM_DBG_HYPER_STEPPED
616 je short .rc_to_host
617 cmp eax, VINF_EM_DBG_HYPER_BREAKPOINT
618 je short .rc_to_host
619 cmp eax, VINF_EM_DBG_HYPER_ASSERTION
620 je short .rc_to_host
621 jmp .rc_abandon_ship
622
623 ;
624 ; Pop back to the host to service the error.
625 ;
626.rc_to_host:
627 mov edx, IMP(g_VM)
628 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
629 mov eax, VERR_TRPM_DONT_PANIC
630 jmp .rc_to_host
631
632 ;
633 ; Continue(/Resume/Restart/Whatever) hypervisor execution.
634 ; Don't reset the TRPM state. Caller takes care of that.
635 ;
636ALIGNCODE(16)
637.rc_continue:
638%ifdef DEBUG_STUFF
639 mov eax, [%$STK_ERRCD]
640 mov ecx, 'resH' ; indicate trap.
641 mov edx, [%$STK_VECTOR]
642 call trpmDbgDumpRegisterFrame
643%endif
644
645%ifdef VBOX_WITH_STATISTICS
646 mov edx, [%$STK_VECTOR]
647 imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128
648 add edx, TRPM.aStatGCTraps
649 add edx, IMP(g_TRPM)
650 STAM_PROFILE_ADV_STOP edx
651%endif
652
653 ; restore
654 mov eax, [ebx + CPUMCTXCORE.eax]
655 mov [%$STK_SAVED_EAX], eax
656 mov ecx, [ebx + CPUMCTXCORE.ecx]
657 mov edx, [ebx + CPUMCTXCORE.edx]
658 mov eax, [ebx + CPUMCTXCORE.ebx]
659 mov [%$STK_SAVED_EBX], eax
660 mov ebp, [ebx + CPUMCTXCORE.ebp]
661 mov esi, [ebx + CPUMCTXCORE.esi]
662 mov edi, [ebx + CPUMCTXCORE.edi]
663
664 ; skipping esp & ss.
665
666 mov eax, [ebx + CPUMCTXCORE.eflags]
667 mov [%$STK_EFLAGS], eax
668 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
669 mov [%$STK_CS], eax
670 mov eax, [ebx + CPUMCTXCORE.eip]
671 mov [%$STK_EIP], eax
672
673 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
674 mov gs, ax
675
676 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
677 mov fs, ax
678
679 mov ax, [ebx + CPUMCTXCORE.es.Sel]
680 mov es, ax
681
682 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
683 mov ds, ax
684
685 ; finally restore our scratch register eax and ebx.
686 pop ebx
687 pop eax
688 add esp, 16 + 8 ; skip segregs, error code, and vector number.
689
690 iret
691
692
693 ;
694 ; Internal processing error - don't panic, start meditating!
695 ;
696.rc_abandon_ship:
697%ifdef DEBUG_STUFF
698 mov eax, [%$STK_ERRCD]
699 mov ecx, 'trpH' ; indicate trap.
700 mov edx, [%$STK_VECTOR]
701 call trpmDbgDumpRegisterFrame
702%endif
703
704.rc_do_not_panic:
705 mov edx, IMP(g_VM)
706 mov eax, VERR_TRPM_DONT_PANIC
707 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
708%ifdef DEBUG_STUFF
709 COM_S_PRINT 'bad!!!'
710%endif
711 jmp .rc_do_not_panic ; this shall never ever happen!
712%pop
713ENDPROC TRPMGCHandlerGeneric
714
715
716
717
718
719;;
720; We start by 256 push <vector no.> + jmp interruptworker
721;
722ALIGNCODE(16)
723BEGINPROC_EXPORTED TRPMGCHandlerInterupt
724 ; NASM has some nice features, here an example of a loop.
725%assign i 0
726%rep 256
727 db 06ah, i ; push imm8 - note that this is a signextended value.
728 jmp ti_GenericInterrupt
729 ALIGNCODE(8)
730%assign i i+1
731%endrep
732
733;;
734; Main interrupt handler for the guest context
735;
736; Stack:
737; 24 GS (V86 only)
738; 20 FS (V86 only)
739; 1C DS (V86 only)
740; 18 ES (V86 only)
741; 14 SS
742; 10 ESP
743; c EFLAGS
744; 8 CS
745; 4 EIP
746; ESP -> 0 Vector number (only use low byte!).
747;
748; @uses none
749ti_GenericInterrupt:
750 cld
751
752 ;
753 ; Save ds, es, fs, gs, eax and ebx so we have a context pointer (ebx) and
754 ; scratch (eax) register to work with. A sideeffect of using ebx is that
755 ; it's preserved accross cdecl calls.
756 ;
757 ; In order to safely access data, we need to load our flat DS & ES selector,
758 ; clear FS and GS (stale guest selector prevention), and clear make sure
759 ; that CR0.WP is cleared.
760 ;
761 push ds ; +14h
762 push es ; +10h
763 push fs ; +0ch
764 push gs ; +08h
765 push eax ; +04h
766 push ebx ; +00h
767%push StackFrame
768%define %$STK_SAVED_EBX esp
769%define %$STK_SAVED_EAX esp + 04h
770%define %$STK_SAVED_GS esp + 08h
771%define %$STK_SAVED_FS esp + 0ch
772%define %$STK_SAVED_ES esp + 10h
773%define %$STK_SAVED_DS esp + 14h
774%define %$ESPOFF 18h
775%define %$STK_VECTOR esp + 00h + %$ESPOFF
776%define %$STK_EIP esp + 04h + %$ESPOFF
777%define %$STK_CS esp + 08h + %$ESPOFF
778%define %$STK_EFLAGS esp + 0ch + %$ESPOFF
779%define %$STK_ESP esp + 10h + %$ESPOFF
780%define %$STK_SS esp + 14h + %$ESPOFF
781%define %$STK_V86_ES esp + 18h + %$ESPOFF
782%define %$STK_V86_DS esp + 1ch + %$ESPOFF
783%define %$STK_V86_FS esp + 20h + %$ESPOFF
784%define %$STK_V86_GS esp + 24h + %$ESPOFF
785
786 mov bx, ss ; load
787 mov ds, bx
788 mov es, bx
789
790 xor bx, bx ; load 0 into gs and fs.
791 mov gs, bx
792 mov fs, bx
793
794 mov eax, cr0 ;; @todo elimitate this read?
795 and eax, ~X86_CR0_WRITE_PROTECT
796 mov cr0, eax
797
798 mov ebx, IMP(g_trpmGuestCtxCore) ; Assume GC as the most common.
799 test byte [%$STK_CS], 3h ; check RPL of the cs selector
800 jnz .save_guest_state
801 test dword [%$STK_EFLAGS], X86_EFL_VM ; If in V86, then guest.
802 jnz .save_guest_state
803 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
804
805 ;
806 ; Save the state.
807 ;
808.save_hyper_state:
809 mov [ebx + CPUMCTXCORE.ecx], ecx
810 lea eax, [%$STK_ESP]
811 mov [ebx + CPUMCTXCORE.esp], eax
812 mov cx, ss
813 mov [ebx + CPUMCTXCORE.ss.Sel], cx
814 jmp .save_state_common
815
816.save_guest_state:
817 mov [ebx + CPUMCTXCORE.ecx], ecx
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.save_state_common:
824 mov eax, [%$STK_SAVED_EAX]
825 mov [ebx + CPUMCTXCORE.eax], eax
826 mov [ebx + CPUMCTXCORE.edx], edx
827 mov eax, [%$STK_SAVED_EBX]
828 mov [ebx + CPUMCTXCORE.ebx], eax
829 mov [ebx + CPUMCTXCORE.esi], esi
830 mov [ebx + CPUMCTXCORE.edi], edi
831 mov [ebx + CPUMCTXCORE.ebp], ebp
832
833 mov cx, [%$STK_CS]
834 mov [ebx + CPUMCTXCORE.cs.Sel], cx
835 mov eax, [%$STK_EIP]
836 mov [ebx + CPUMCTXCORE.eip], eax
837 mov eax, [%$STK_EFLAGS]
838 mov [ebx + CPUMCTXCORE.eflags], eax
839
840%if GC_ARCH_BITS == 64 ; zero out the high dwords - probably not necessary any more.
841 mov dword [ebx + CPUMCTXCORE.eax + 4], 0
842 mov dword [ebx + CPUMCTXCORE.ecx + 4], 0
843 mov dword [ebx + CPUMCTXCORE.edx + 4], 0
844 mov dword [ebx + CPUMCTXCORE.ebx + 4], 0
845 mov dword [ebx + CPUMCTXCORE.esi + 4], 0
846 mov dword [ebx + CPUMCTXCORE.edi + 4], 0
847 mov dword [ebx + CPUMCTXCORE.ebp + 4], 0
848 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
849 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
850%endif
851
852 test dword [%$STK_EFLAGS], X86_EFL_VM
853 jnz .save_V86_segregs
854
855 mov cx, [%$STK_SAVED_ES]
856 mov [ebx + CPUMCTXCORE.es.Sel], cx
857 mov cx, [%$STK_SAVED_DS]
858 mov [ebx + CPUMCTXCORE.ds.Sel], cx
859 mov cx, [%$STK_SAVED_FS]
860 mov [ebx + CPUMCTXCORE.fs.Sel], cx
861 mov cx, [%$STK_SAVED_GS]
862 mov [ebx + CPUMCTXCORE.gs.Sel], cx
863 jmp .done_saving
864
865 ;
866 ; The DS, ES, FS and GS registers are zeroed in V86 mode and their real
867 ; values are on the stack.
868 ;
869.save_V86_segregs:
870 mov cx, [%$STK_V86_ES]
871 mov [ebx + CPUMCTXCORE.es.Sel], cx
872 mov cx, [%$STK_V86_DS]
873 mov [ebx + CPUMCTXCORE.ds.Sel], cx
874 mov cx, [%$STK_V86_FS]
875 mov [ebx + CPUMCTXCORE.fs.Sel], cx
876 mov cx, [%$STK_V86_GS]
877 mov [ebx + CPUMCTXCORE.gs.Sel], cx
878
879.done_saving:
880
881 ;
882 ; Store the information about the active trap/interrupt.
883 ;
884 mov esi, IMP(g_TRPMCPU) ; esi = TRPMCPU until resume!
885 movzx edx, byte [%$STK_VECTOR]
886 mov [esi + TRPMCPU.uActiveVector], edx
887 mov dword [esi + TRPMCPU.uActiveErrorCode], 0
888 mov dword [esi + TRPMCPU.enmActiveType], TRPM_TRAP
889 mov dword [esi + TRPMCPU.uActiveCR2], edx
890%if GC_ARCH_BITS == 64 ; zero out the high dwords.
891 mov dword [esi + TRPMCPU.uActiveErrorCode + 4], 0
892 mov dword [esi + TRPMCPU.uActiveCR2 + 4], 0
893%endif
894
895%ifdef VBOX_WITH_STATISTICS
896 ;
897 ; Update statistics.
898 ;
899 mov edi, IMP(g_TRPM)
900 movzx edx, byte [%$STK_VECTOR] ; vector number
901 imul edx, edx, byte STAMCOUNTER_size
902 add edx, [edi + TRPM.paStatHostIrqRC]
903 STAM_COUNTER_INC edx
904%endif
905
906 ;
907 ; Check if we're in the raw-mode context (RC / hypervisor) when this happened.
908 ;
909 test dword [%$STK_EFLAGS], X86_EFL_VM
910 jnz short .gc_not_raw_mode_context
911
912 test byte [%$STK_CS], 3h ; check RPL of the cs selector
913 jz .rc_in_raw_mode_context
914
915 ;
916 ; Trap in guest code.
917 ;
918.gc_not_raw_mode_context:
919 and dword [ebx + CPUMCTXCORE.eflags], ~X86_EFL_RF ; Clear RF.
920 ; The guest shall not see this in it's state.
921%ifdef DEBUG_STUFF_INT
922 xor eax, eax
923 mov ecx, 'intG' ; indicate trap in GC.
924 movzx edx, byte [%$STK_VECTOR]
925 call trpmDbgDumpRegisterFrame
926%endif
927
928 ;
929 ; Switch back to the host and process it there.
930 ;
931 mov edx, IMP(g_VM)
932 mov eax, VINF_EM_RAW_INTERRUPT
933 call [edx + VM.pfnVMMRCToHostAsm]
934
935 ;
936 ; We've returned!
937 ;
938
939 ; Reset TRPM state
940 xor edx, edx
941 dec edx ; edx = 0ffffffffh
942 xchg [esi + TRPMCPU.uActiveVector], edx
943 mov [esi + TRPMCPU.uPrevVector], edx
944
945%ifdef VBOX_STRICT
946 ; Call CPUM to check sanity.
947 mov edx, IMP(g_VM)
948 push edx
949 call NAME(CPUMRCAssertPreExecutionSanity)
950 add esp, 4
951%endif
952
953 ; enable WP
954 mov eax, cr0 ;; @todo try elimiate this read.
955 or eax, X86_CR0_WRITE_PROTECT
956 mov cr0, eax
957
958 ; restore guest state and start executing again.
959 mov eax, [ebx + CPUMCTXCORE.eax]
960 mov [%$STK_SAVED_EAX], eax
961 mov ecx, [ebx + CPUMCTXCORE.ecx]
962 mov edx, [ebx + CPUMCTXCORE.edx]
963 mov eax, [ebx + CPUMCTXCORE.ebx]
964 mov [%$STK_SAVED_EBX], eax
965 mov ebp, [ebx + CPUMCTXCORE.ebp]
966 mov esi, [ebx + CPUMCTXCORE.esi]
967 mov edi, [ebx + CPUMCTXCORE.edi]
968
969 mov eax, [ebx + CPUMCTXCORE.esp]
970 mov [%$STK_ESP], eax
971 mov eax, dword [ebx + CPUMCTXCORE.ss.Sel]
972 mov [%$STK_SS], eax
973 mov eax, [ebx + CPUMCTXCORE.eflags]
974 mov [%$STK_EFLAGS], eax
975 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
976 mov [%$STK_CS], eax
977 mov eax, [ebx + CPUMCTXCORE.eip]
978 mov [%$STK_EIP], eax
979
980 test dword [ebx + CPUMCTXCORE.eflags], X86_EFL_VM
981 jnz .gc_V86_return
982
983 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
984 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
985 mov gs, ax
986
987 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
988 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
989 mov fs, ax
990
991 mov ax, [ebx + CPUMCTXCORE.es.Sel]
992 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
993 mov es, ax
994
995 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
996 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
997 mov ds, ax
998
999 ; finally restore our scratch register eax and ebx.
1000 pop ebx
1001 pop eax
1002 add esp, 16 + 4 ; skip segregs, and vector number.
1003
1004 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET
1005 iret
1006
1007ALIGNCODE(16)
1008.gc_V86_return:
1009 mov eax, dword [ebx + CPUMCTXCORE.es.Sel]
1010 mov [%$STK_V86_ES], eax
1011 mov eax, dword [ebx + CPUMCTXCORE.ds.Sel]
1012 mov [%$STK_V86_DS], eax
1013 mov eax, dword [ebx + CPUMCTXCORE.fs.Sel]
1014 mov [%$STK_V86_FS], eax
1015 mov eax, dword [ebx + CPUMCTXCORE.gs.Sel]
1016 mov [%$STK_V86_GS], eax
1017
1018 ; finally restore our scratch register eax and ebx.
1019 pop ebx
1020 pop eax
1021 add esp, 16 + 4 ; skip segregs, and vector number.
1022
1023 TRPM_NP_GP_HANDLER NAME(trpmRCTrapInGeneric), TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86
1024 iret
1025
1026 ; -+- Entry point -+-
1027 ;
1028 ; We're in hypervisor mode which means no guest context
1029 ; and special care to be taken to restore the hypervisor
1030 ; context correctly.
1031 ;
1032 ; ATM the only place this can happen is when entering a trap handler.
1033 ; We make ASSUMPTIONS about this in respects to the WP CR0 bit
1034 ;
1035ALIGNCODE(16)
1036.rc_in_raw_mode_context:
1037 ; fix ss:esp.
1038 lea ecx, [%$STK_ESP] ; calc esp at trap
1039 mov [ebx + CPUMCTXCORE.esp], ecx ; update esp in register frame
1040 mov [ebx + CPUMCTXCORE.ss.Sel], ss ; update ss in register frame
1041
1042%ifdef DEBUG_STUFF_INT
1043 xor eax, eax
1044 mov ecx, 'intH' ; indicate trap in RC.
1045 movzx edx, byte [%$STK_VECTOR]
1046 call trpmDbgDumpRegisterFrame
1047%endif
1048
1049 mov edx, IMP(g_VM)
1050 mov eax, VINF_EM_RAW_INTERRUPT_HYPER
1051 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
1052%ifdef DEBUG_STUFF_INT
1053 COM_S_CHAR '!'
1054%endif
1055
1056 ;
1057 ; We've returned!
1058 ; Continue(/Resume/Restart/Whatever) hypervisor execution.
1059 ;
1060
1061 ; Reset TRPM state - don't record this.
1062 ;mov esi, IMP(g_TRPMCPU)
1063 mov dword [esi + TRPMCPU.uActiveVector], 0ffffffffh
1064
1065 ;
1066 ; Restore the hypervisor context and return.
1067 ;
1068 mov eax, [ebx + CPUMCTXCORE.eax]
1069 mov [%$STK_SAVED_EAX], eax
1070 mov ecx, [ebx + CPUMCTXCORE.ecx]
1071 mov edx, [ebx + CPUMCTXCORE.edx]
1072 mov eax, [ebx + CPUMCTXCORE.ebx]
1073 mov [%$STK_SAVED_EBX], eax
1074 mov ebp, [ebx + CPUMCTXCORE.ebp]
1075 mov esi, [ebx + CPUMCTXCORE.esi]
1076 mov edi, [ebx + CPUMCTXCORE.edi]
1077
1078 ; skipping esp & ss.
1079
1080 mov eax, [ebx + CPUMCTXCORE.eflags]
1081 mov [%$STK_EFLAGS], eax
1082 mov eax, dword [ebx + CPUMCTXCORE.cs.Sel]
1083 mov [%$STK_CS], eax
1084 mov eax, [ebx + CPUMCTXCORE.eip]
1085 mov [%$STK_EIP], eax
1086
1087 mov ax, [ebx + CPUMCTXCORE.gs.Sel]
1088 mov gs, ax
1089
1090 mov ax, [ebx + CPUMCTXCORE.fs.Sel]
1091 mov fs, ax
1092
1093 mov ax, [ebx + CPUMCTXCORE.es.Sel]
1094 mov es, ax
1095
1096 mov ax, [ebx + CPUMCTXCORE.ds.Sel]
1097 mov ds, ax
1098
1099 ; finally restore our scratch register eax and ebx.
1100 pop ebx
1101 pop eax
1102 add esp, 16 + 4 ; skip segregs, and vector number.
1103
1104 iret
1105%pop
1106ENDPROC TRPMGCHandlerInterupt
1107
1108
1109
1110;;
1111; Trap handler for #MC
1112;
1113; This handler will forward the #MC to the host OS. Since this
1114; is generalized in the generic interrupt handler, we just disable
1115; interrupts and push vector number and jump to the generic code.
1116;
1117; Stack:
1118; 10 SS (only if ring transition.)
1119; c ESP (only if ring transition.)
1120; 8 EFLAGS
1121; 4 CS
1122; 0 EIP
1123;
1124; @uses none
1125;
1126ALIGNCODE(16)
1127BEGINPROC_EXPORTED TRPMGCHandlerTrap12
1128 push byte 12h
1129 jmp ti_GenericInterrupt
1130ENDPROC TRPMGCHandlerTrap12
1131
1132
1133
1134
1135;;
1136; Trap handler for double fault (#DF).
1137;
1138; This is a special trap handler executes in separate task with own TSS, with
1139; one of the intermediate memory contexts instead of the shadow context.
1140; The handler will unconditionally print an report to the comport configured
1141; for the COM_S_* macros before attempting to return to the host. If it it ends
1142; up double faulting more than 10 times, it will simply cause an triple fault
1143; to get us out of the mess.
1144;
1145; @param esp Half way down the hypervisor stack + the trap frame.
1146; @param ebp Half way down the hypervisor stack.
1147; @param eflags Interrupts disabled, nested flag is probably set (we don't care).
1148; @param ecx The address of the hypervisor TSS.
1149; @param edi Same as ecx.
1150; @param eax Same as ecx.
1151; @param edx Address of the VM structure.
1152; @param esi Same as edx.
1153; @param ebx Same as edx.
1154; @param ss Hypervisor DS.
1155; @param ds Hypervisor DS.
1156; @param es Hypervisor DS.
1157; @param fs 0
1158; @param gs 0
1159;
1160;
1161; @remark To be able to catch errors with WP turned off, it is required that the
1162; TSS GDT descriptor and the TSSes are writable (X86_PTE_RW). See SELM.cpp
1163; for how to enable this.
1164;
1165; @remark It is *not* safe to resume the VMM after a double fault. (At least not
1166; without clearing the busy flag of the TssTrap8 and fixing whatever cause it.)
1167;
1168ALIGNCODE(16)
1169BEGINPROC_EXPORTED TRPMGCHandlerTrap08
1170 ; be careful.
1171 cli
1172 cld
1173
1174 ;
1175 ; Disable write protection.
1176 ;
1177 mov eax, cr0
1178 and eax, ~X86_CR0_WRITE_PROTECT
1179 mov cr0, eax
1180
1181 ;
1182 ; Load Hypervisor DS and ES (get it from the SS) - paranoia, but the TSS could be overwritten.. :)
1183 ;
1184 mov eax, ss
1185 mov ds, eax
1186 mov es, eax
1187
1188 COM_S_PRINT 10,13,'*** Guru Meditation 00000008 - Double Fault! ***',10,13
1189
1190 COM_S_PRINT 'VM='
1191 COM_S_DWORD_REG edx
1192 COM_S_PRINT ' prevTSS='
1193 COM_S_DWORD_REG ecx
1194 COM_S_PRINT ' prevCR3='
1195 mov eax, [ecx + VBOXTSS.cr3]
1196 COM_S_DWORD_REG eax
1197 COM_S_PRINT ' prevLdtr='
1198 movzx eax, word [ecx + VBOXTSS.selLdt]
1199 COM_S_DWORD_REG eax
1200 COM_S_NEWLINE
1201
1202 ;
1203 ; Create CPUMCTXCORE structure.
1204 ;
1205 mov ebx, IMP(g_trpmHyperCtxCore) ; It's raw-mode context, actually.
1206
1207 mov eax, [ecx + VBOXTSS.eip]
1208 mov [ebx + CPUMCTXCORE.eip], eax
1209%if GC_ARCH_BITS == 64
1210 ; zero out the high dword
1211 mov dword [ebx + CPUMCTXCORE.eip + 4], 0
1212%endif
1213 mov eax, [ecx + VBOXTSS.eflags]
1214 mov [ebx + CPUMCTXCORE.eflags], eax
1215
1216 movzx eax, word [ecx + VBOXTSS.cs]
1217 mov dword [ebx + CPUMCTXCORE.cs.Sel], eax
1218 movzx eax, word [ecx + VBOXTSS.ds]
1219 mov dword [ebx + CPUMCTXCORE.ds.Sel], eax
1220 movzx eax, word [ecx + VBOXTSS.es]
1221 mov dword [ebx + CPUMCTXCORE.es.Sel], eax
1222 movzx eax, word [ecx + VBOXTSS.fs]
1223 mov dword [ebx + CPUMCTXCORE.fs.Sel], eax
1224 movzx eax, word [ecx + VBOXTSS.gs]
1225 mov dword [ebx + CPUMCTXCORE.gs.Sel], eax
1226 movzx eax, word [ecx + VBOXTSS.ss]
1227 mov [ebx + CPUMCTXCORE.ss.Sel], eax
1228 mov eax, [ecx + VBOXTSS.esp]
1229 mov [ebx + CPUMCTXCORE.esp], eax
1230%if GC_ARCH_BITS == 64
1231 ; zero out the high dword
1232 mov dword [ebx + CPUMCTXCORE.esp + 4], 0
1233%endif
1234 mov eax, [ecx + VBOXTSS.ecx]
1235 mov [ebx + CPUMCTXCORE.ecx], eax
1236 mov eax, [ecx + VBOXTSS.edx]
1237 mov [ebx + CPUMCTXCORE.edx], eax
1238 mov eax, [ecx + VBOXTSS.ebx]
1239 mov [ebx + CPUMCTXCORE.ebx], eax
1240 mov eax, [ecx + VBOXTSS.eax]
1241 mov [ebx + CPUMCTXCORE.eax], eax
1242 mov eax, [ecx + VBOXTSS.ebp]
1243 mov [ebx + CPUMCTXCORE.ebp], eax
1244 mov eax, [ecx + VBOXTSS.esi]
1245 mov [ebx + CPUMCTXCORE.esi], eax
1246 mov eax, [ecx + VBOXTSS.edi]
1247 mov [ebx + CPUMCTXCORE.edi], eax
1248
1249 ;
1250 ; Show regs
1251 ;
1252 mov eax, 0ffffffffh
1253 mov ecx, 'trpH' ; indicate trap.
1254 mov edx, 08h ; vector number
1255 call trpmDbgDumpRegisterFrame
1256
1257 ;
1258 ; Should we try go back?
1259 ;
1260 inc dword [df_Count]
1261 cmp dword [df_Count], byte 10
1262 jb df_to_host
1263 jmp df_tripple_fault
1264df_Count: dd 0
1265
1266 ;
1267 ; Try return to the host.
1268 ;
1269df_to_host:
1270 COM_S_PRINT 'Trying to return to host...',10,13
1271 mov edx, IMP(g_VM)
1272 mov eax, VERR_TRPM_PANIC
1273 call [edx + VM.pfnVMMRCToHostAsmNoReturn]
1274 jmp short df_to_host
1275
1276 ;
1277 ; Perform a tripple fault.
1278 ;
1279df_tripple_fault:
1280 COM_S_PRINT 'Giving up - tripple faulting the machine...',10,13
1281 push byte 0
1282 push byte 0
1283 sidt [esp]
1284 mov word [esp], 0
1285 lidt [esp]
1286 xor eax, eax
1287 mov dword [eax], 0
1288 jmp df_tripple_fault
1289
1290ENDPROC TRPMGCHandlerTrap08
1291
1292
1293
1294
1295;;
1296; Internal procedure used to dump registers.
1297;
1298; @param ebx Pointer to CPUMCTXCORE.
1299; @param edx Vector number
1300; @param ecx 'trap' if trap, 'int' if interrupt.
1301; @param eax Error code if trap.
1302;
1303trpmDbgDumpRegisterFrame:
1304 sub esp, byte 8 ; working space for sidt/sgdt/etc
1305
1306; Init _must_ be done on host before crashing!
1307; push edx
1308; push eax
1309; COM_INIT
1310; pop eax
1311; pop edx
1312
1313 cmp ecx, 'trpH'
1314 je near tddrf_trpH
1315 cmp ecx, 'trpG'
1316 je near tddrf_trpG
1317 cmp ecx, 'intH'
1318 je near tddrf_intH
1319 cmp ecx, 'intG'
1320 je near tddrf_intG
1321 cmp ecx, 'resH'
1322 je near tddrf_resH
1323 COM_S_PRINT 10,13,'*** Bogus Dump Code '
1324 jmp tddrf_regs
1325
1326%if 1 ; the verbose version
1327
1328tddrf_intG:
1329 COM_S_PRINT 10,13,'*** Interrupt (Guest) '
1330 COM_S_DWORD_REG edx
1331 jmp tddrf_regs
1332
1333tddrf_intH:
1334 COM_S_PRINT 10,13,'*** Interrupt (Hypervisor) '
1335 COM_S_DWORD_REG edx
1336 jmp tddrf_regs
1337
1338tddrf_trpG:
1339 COM_S_PRINT 10,13,'*** Trap '
1340 jmp tddrf_trap_rest
1341
1342%else ; the short version
1343
1344tddrf_intG:
1345 COM_S_CHAR 'I'
1346 jmp tddrf_ret
1347
1348tddrf_intH:
1349 COM_S_CHAR 'i'
1350 jmp tddrf_ret
1351
1352tddrf_trpG:
1353 COM_S_CHAR 'T'
1354 jmp tddrf_ret
1355
1356%endif ; the short version
1357
1358tddrf_trpH:
1359 COM_S_PRINT 10,13,'*** Guru Meditation '
1360 jmp tddrf_trap_rest
1361
1362tddrf_resH:
1363 COM_S_PRINT 10,13,'*** Resuming Hypervisor Trap '
1364 jmp tddrf_trap_rest
1365
1366tddrf_trap_rest:
1367 COM_S_DWORD_REG edx
1368 COM_S_PRINT ' ErrorCode='
1369 COM_S_DWORD_REG eax
1370 COM_S_PRINT ' cr2='
1371 mov ecx, cr2
1372 COM_S_DWORD_REG ecx
1373
1374tddrf_regs:
1375 COM_S_PRINT ' ***',10,13,'cs:eip='
1376 movzx ecx, word [ebx + CPUMCTXCORE.cs.Sel]
1377 COM_S_DWORD_REG ecx
1378 COM_S_CHAR ':'
1379 mov ecx, [ebx + CPUMCTXCORE.eip]
1380 COM_S_DWORD_REG ecx
1381
1382 COM_S_PRINT ' ss:esp='
1383 movzx ecx, word [ebx + CPUMCTXCORE.ss.Sel]
1384 COM_S_DWORD_REG ecx
1385 COM_S_CHAR ':'
1386 mov ecx, [ebx + CPUMCTXCORE.esp]
1387 COM_S_DWORD_REG ecx
1388
1389
1390 sgdt [esp]
1391 COM_S_PRINT 10,13,' gdtr='
1392 movzx ecx, word [esp]
1393 COM_S_DWORD_REG ecx
1394 COM_S_CHAR ':'
1395 mov ecx, [esp + 2]
1396 COM_S_DWORD_REG ecx
1397
1398 sidt [esp]
1399 COM_S_PRINT ' idtr='
1400 movzx ecx, word [esp]
1401 COM_S_DWORD_REG ecx
1402 COM_S_CHAR ':'
1403 mov ecx, [esp + 2]
1404 COM_S_DWORD_REG ecx
1405
1406
1407 str [esp] ; yasm BUG! it generates sldt [esp] here! YASMCHECK!
1408 COM_S_PRINT 10,13,' tr='
1409 movzx ecx, word [esp]
1410 COM_S_DWORD_REG ecx
1411
1412 sldt [esp]
1413 COM_S_PRINT ' ldtr='
1414 movzx ecx, word [esp]
1415 COM_S_DWORD_REG ecx
1416
1417 COM_S_PRINT ' eflags='
1418 mov ecx, [ebx + CPUMCTXCORE.eflags]
1419 COM_S_DWORD_REG ecx
1420
1421
1422 COM_S_PRINT 10,13,'cr0='
1423 mov ecx, cr0
1424 COM_S_DWORD_REG ecx
1425
1426 COM_S_PRINT ' cr2='
1427 mov ecx, cr2
1428 COM_S_DWORD_REG ecx
1429
1430 COM_S_PRINT ' cr3='
1431 mov ecx, cr3
1432 COM_S_DWORD_REG ecx
1433 COM_S_PRINT ' cr4='
1434 mov ecx, cr4
1435 COM_S_DWORD_REG ecx
1436
1437
1438 COM_S_PRINT 10,13,' ds='
1439 movzx ecx, word [ebx + CPUMCTXCORE.ds.Sel]
1440 COM_S_DWORD_REG ecx
1441
1442 COM_S_PRINT ' es='
1443 movzx ecx, word [ebx + CPUMCTXCORE.es.Sel]
1444 COM_S_DWORD_REG ecx
1445
1446 COM_S_PRINT ' fs='
1447 movzx ecx, word [ebx + CPUMCTXCORE.fs.Sel]
1448 COM_S_DWORD_REG ecx
1449
1450 COM_S_PRINT ' gs='
1451 movzx ecx, word [ebx + CPUMCTXCORE.gs.Sel]
1452 COM_S_DWORD_REG ecx
1453
1454
1455 COM_S_PRINT 10,13,'eax='
1456 mov ecx, [ebx + CPUMCTXCORE.eax]
1457 COM_S_DWORD_REG ecx
1458
1459 COM_S_PRINT ' ebx='
1460 mov ecx, [ebx + CPUMCTXCORE.ebx]
1461 COM_S_DWORD_REG ecx
1462
1463 COM_S_PRINT ' ecx='
1464 mov ecx, [ebx + CPUMCTXCORE.ecx]
1465 COM_S_DWORD_REG ecx
1466
1467 COM_S_PRINT ' edx='
1468 mov ecx, [ebx + CPUMCTXCORE.edx]
1469 COM_S_DWORD_REG ecx
1470
1471
1472 COM_S_PRINT 10,13,'esi='
1473 mov ecx, [ebx + CPUMCTXCORE.esi]
1474 COM_S_DWORD_REG ecx
1475
1476 COM_S_PRINT ' edi='
1477 mov ecx, [ebx + CPUMCTXCORE.edi]
1478 COM_S_DWORD_REG ecx
1479
1480 COM_S_PRINT ' ebp='
1481 mov ecx, [ebx + CPUMCTXCORE.ebp]
1482 COM_S_DWORD_REG ecx
1483
1484
1485 COM_S_NEWLINE
1486
1487tddrf_ret:
1488 add esp, byte 8
1489 ret
1490
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