VirtualBox

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

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

scm --update-copyright-year

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