1
; $Id: TRPMGCHandlersA.asm 4394 2007-08-27 19:41:25Z vboxsync $
3
; TRPM - Guest Context Trap Handlers
6
; Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
12
; in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13
; distribution. VirtualBox OSE is distributed in the hope that it will
14
; be useful, but WITHOUT ANY WARRANTY of any kind.
16
;*******************************************************************************
18
;*******************************************************************************
20
%include "VBox/x86.mac"
21
%include "VBox/cpum.mac"
22
%include "VBox/stam.mac"
23
%include "VBox/vm.mac"
24
%include "TRPMInternal.mac"
25
%include "VBox/err.mac"
26
%include "VBox/trpm.mac"
29
;*******************************************************************************
31
;*******************************************************************************
32
extern IMPNAME(g_CPUM) ; These IMPNAME(g_*) symbols resolve to the import table
33
extern IMPNAME(g_TRPM) ; where there is a pointer to the real symbol. PE imports
34
extern IMPNAME(g_VM) ; are a bit confusing at first... :-)
35
extern NAME(CPUMGCRestoreInt)
36
extern NAME(CPUMHandleLazyFPUAsm)
37
extern NAME(CPUMHyperSetCtxCore)
38
extern NAME(trpmGCTrapInGeneric)
39
extern NAME(TRPMGCHyperTrap0bHandler)
40
extern NAME(TRPMGCHyperTrap0dHandler)
41
extern NAME(TRPMGCHyperTrap0eHandler)
42
extern NAME(TRPMGCTrap01Handler)
44
extern NAME(TRPMGCTrap02Handler)
46
extern NAME(TRPMGCTrap03Handler)
47
extern NAME(TRPMGCTrap06Handler)
48
extern NAME(TRPMGCTrap0bHandler)
49
extern NAME(TRPMGCTrap0dHandler)
50
extern NAME(TRPMGCTrap0eHandler)
51
extern NAME(TRPMGCTrap07Handler)
53
;; IMPORTANT all COM_ functions trashes esi, some edi and the LOOP_SHORT_WHILE kills ecx.
54
;%define DEBUG_STUFF 1
55
;%define DEBUG_STUFF_TRPG 1
56
;%define DEBUG_STUFF_INT 1
61
; Jump table for trap handlers for hypervisor traps.
63
g_apfnStaticTrapHandlersHyper:
64
; N - M M - T - C - D i
65
; o - n o - y - o - e p
69
; =============================================================
70
dd 0 ; 0 - #DE - F - N - Divide error
71
dd NAME(TRPMGCTrap01Handler) ; 1 - #DB - F/T - N - Single step, INT 1 instruction
73
dd NAME(TRPMGCTrap02Handler) ; 2 - - I - N - Non-Maskable Interrupt (NMI)
75
dd 0 ; 2 - - I - N - Non-Maskable Interrupt (NMI)
77
dd NAME(TRPMGCTrap03Handler) ; 3 - #BP - T - N - Breakpoint, INT 3 instruction.
78
dd 0 ; 4 - #OF - T - N - Overflow, INTO instruction.
79
dd 0 ; 5 - #BR - F - N - BOUND Range Exceeded, BOUND instruction.
80
dd 0 ; 6 - #UD - F - N - Undefined(/Invalid) Opcode.
81
dd 0 ; 7 - #NM - F - N - Device not available, FP or (F)WAIT instruction.
82
dd 0 ; 8 - #DF - A - 0 - Double fault.
83
dd 0 ; 9 - - F - N - Coprocessor Segment Overrun (obsolete).
84
dd 0 ; a - #TS - F - Y - Invalid TSS, Taskswitch or TSS access.
85
dd NAME(TRPMGCHyperTrap0bHandler) ; b - #NP - F - Y - Segment not present.
86
dd 0 ; c - #SS - F - Y - Stack-Segment fault.
87
dd NAME(TRPMGCHyperTrap0dHandler) ; d - #GP - F - Y - General protection fault.
88
dd NAME(TRPMGCHyperTrap0eHandler) ; e - #PF - F - Y - Page fault.
89
dd 0 ; f - - - - Intel Reserved. Do not use.
90
dd 0 ; 10 - #MF - F - N - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction.
91
dd 0 ; 11 - #AC - F - 0 - Alignment Check.
92
dd 0 ; 12 - #MC - A - N - Machine Check.
93
dd 0 ; 13 - #XF - F - N - SIMD Floating-Point Exception.
94
dd 0 ; 14 - - - - Intel Reserved. Do not use.
95
dd 0 ; 15 - - - - Intel Reserved. Do not use.
96
dd 0 ; 16 - - - - Intel Reserved. Do not use.
97
dd 0 ; 17 - - - - Intel Reserved. Do not use.
98
dd 0 ; 18 - - - - Intel Reserved. Do not use.
102
; Jump table for trap handlers for guest traps
104
g_apfnStaticTrapHandlersGuest:
105
; N - M M - T - C - D i
106
; o - n o - y - o - e p
107
; - e n - p - d - s t
110
; =============================================================
111
dd 0 ; 0 - #DE - F - N - Divide error
112
dd NAME(TRPMGCTrap01Handler) ; 1 - #DB - F/T - N - Single step, INT 1 instruction
114
dd NAME(TRPMGCTrap02Handler) ; 2 - - I - N - Non-Maskable Interrupt (NMI)
116
dd 0 ; 2 - - I - N - Non-Maskable Interrupt (NMI)
118
dd NAME(TRPMGCTrap03Handler) ; 3 - #BP - T - N - Breakpoint, INT 3 instruction.
119
dd 0 ; 4 - #OF - T - N - Overflow, INTO instruction.
120
dd 0 ; 5 - #BR - F - N - BOUND Range Exceeded, BOUND instruction.
121
dd NAME(TRPMGCTrap06Handler) ; 6 - #UD - F - N - Undefined(/Invalid) Opcode.
122
dd NAME(TRPMGCTrap07Handler) ; 7 - #NM - F - N - Device not available, FP or (F)WAIT instruction.
123
dd 0 ; 8 - #DF - A - 0 - Double fault.
124
dd 0 ; 9 - - F - N - Coprocessor Segment Overrun (obsolete).
125
dd 0 ; a - #TS - F - Y - Invalid TSS, Taskswitch or TSS access.
126
dd NAME(TRPMGCTrap0bHandler) ; b - #NP - F - Y - Segment not present.
127
dd 0 ; c - #SS - F - Y - Stack-Segment fault.
128
dd NAME(TRPMGCTrap0dHandler) ; d - #GP - F - Y - General protection fault.
129
dd NAME(TRPMGCTrap0eHandler) ; e - #PF - F - Y - Page fault.
130
dd 0 ; f - - - - Intel Reserved. Do not use.
131
dd 0 ; 10 - #MF - F - N - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction.
132
dd 0 ; 11 - #AC - F - 0 - Alignment Check.
133
dd 0 ; 12 - #MC - A - N - Machine Check.
134
dd 0 ; 13 - #XF - F - N - SIMD Floating-Point Exception.
135
dd 0 ; 14 - - - - Intel Reserved. Do not use.
136
dd 0 ; 15 - - - - Intel Reserved. Do not use.
137
dd 0 ; 16 - - - - Intel Reserved. Do not use.
138
dd 0 ; 17 - - - - Intel Reserved. Do not use.
139
dd 0 ; 18 - - - - Intel Reserved. Do not use.
144
; We start by 24 push <vector no.> + jmp <generic entry point>
147
BEGINPROC_EXPORTED TRPMGCHandlerGeneric
148
%macro TRPMGenericEntry 1
149
cli ; not disabled for traps it seems.
150
db 06ah, i ; push imm8 - note that this is a signextended value.
156
%assign i 0 ; start counter.
157
TRPMGenericEntry GenericTrap ; 0
158
TRPMGenericEntry GenericTrap ; 1
159
TRPMGenericEntry GenericTrap ; 2
160
TRPMGenericEntry GenericTrap ; 3
161
TRPMGenericEntry GenericTrap ; 4
162
TRPMGenericEntry GenericTrap ; 5
163
TRPMGenericEntry GenericTrap ; 6
164
TRPMGenericEntry GenericTrap ; 7
165
TRPMGenericEntry GenericTrapErrCode ; 8
166
TRPMGenericEntry GenericTrap ; 9
167
TRPMGenericEntry GenericTrapErrCode ; a
168
TRPMGenericEntry GenericTrapErrCode ; b
169
TRPMGenericEntry GenericTrapErrCode ; c
170
TRPMGenericEntry GenericTrapErrCode ; d
171
TRPMGenericEntry GenericTrapErrCode ; e
172
TRPMGenericEntry GenericTrap ; f (reserved)
173
TRPMGenericEntry GenericTrap ; 10
174
TRPMGenericEntry GenericTrapErrCode ; 11
175
TRPMGenericEntry GenericTrap ; 12
176
TRPMGenericEntry GenericTrap ; 13
177
TRPMGenericEntry GenericTrap ; 14 (reserved)
178
TRPMGenericEntry GenericTrap ; 15 (reserved)
179
TRPMGenericEntry GenericTrap ; 16 (reserved)
180
TRPMGenericEntry GenericTrap ; 17 (reserved)
182
%undef TRPMGenericEntry
185
; Main exception handler for the guest context
200
; for the present we fake an error code ~0
204
xchg [esp + 4], eax ; get vector number, set error code
205
xchg [esp], eax ; get saved eax, set vector number
206
jmp short GenericTrapErrCode
210
; Main exception handler for the guest context with error code
217
; 18 SS (only if ring transition.)
218
; 14 ESP (only if ring transition.)
222
; 4 Error code. (~0 for vectors which don't take an error code.)
229
; reserved segment TI IDT EXT
230
; selector GDT/LDT (1) IDT External interrupt
231
; index (IDT=0) index
233
; NOTE: Page faults (trap 14) have a different error code
242
; Setup CPUMCTXCORE frame
244
; ASSUMPTION: If trap in hypervisor, we assume that we can read two dword
245
; under the bottom of the stack. This is atm safe.
246
; ASSUMPTION: There is sufficient stack space.
247
; ASSUMPTION: The stack is not write protected.
249
%define ESPOFF CPUMCTXCORE_size
251
sub esp, CPUMCTXCORE_size
252
mov [esp + CPUMCTXCORE.eax], eax
253
mov [esp + CPUMCTXCORE.ecx], ecx
254
mov [esp + CPUMCTXCORE.edx], edx
255
mov [esp + CPUMCTXCORE.ebx], ebx
256
mov [esp + CPUMCTXCORE.esi], esi
257
mov [esp + CPUMCTXCORE.edi], edi
258
mov [esp + CPUMCTXCORE.ebp], ebp
260
mov eax, [esp + 14h + ESPOFF] ; esp
261
mov [esp + CPUMCTXCORE.esp], eax
262
mov eax, [esp + 18h + ESPOFF] ; ss
263
mov dword [esp + CPUMCTXCORE.ss], eax
265
mov eax, [esp + 0ch + ESPOFF] ; cs
266
mov dword [esp + CPUMCTXCORE.cs], eax
267
mov eax, [esp + 08h + ESPOFF] ; eip
268
mov [esp + CPUMCTXCORE.eip], eax
269
mov eax, [esp + 10h + ESPOFF] ; eflags
270
mov [esp + CPUMCTXCORE.eflags], eax
273
mov dword [esp + CPUMCTXCORE.es], eax
275
mov dword [esp + CPUMCTXCORE.ds], eax
277
mov dword [esp + CPUMCTXCORE.fs], eax
279
mov dword [esp + CPUMCTXCORE.gs], eax
281
test dword [esp + CPUMCTXCORE.eflags], X86_EFL_VM
282
jz short gt_SkipV86Entry
285
; The DS, ES, FS and GS registers are zeroed in V86 mode and their real values are on the stack
287
mov eax, dword [esp + ESPOFF + 1Ch]
288
mov dword [esp + CPUMCTXCORE.es], eax
290
mov eax, dword [esp + ESPOFF + 20h]
291
mov dword [esp + CPUMCTXCORE.ds], eax
293
mov eax, dword [esp + ESPOFF + 24h]
294
mov dword [esp + CPUMCTXCORE.fs], eax
296
mov eax, dword [esp + ESPOFF + 28h]
297
mov dword [esp + CPUMCTXCORE.gs], eax
304
and eax, ~X86_CR0_WRITE_PROTECT
308
; Load Hypervisor DS and ES (get it from the SS)
314
%ifdef VBOX_WITH_STATISTICS
318
mov edx, [esp + 0h + ESPOFF] ; vector number
319
imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128.
320
add edx, TRPM.aStatGCTraps
322
STAM_PROFILE_ADV_START edx
326
; Store the information about the active trap/interrupt.
329
movzx edx, byte [esp + 0h + ESPOFF] ; vector number
330
mov [eax + TRPM.uActiveVector], edx
331
mov edx, [esp + 4h + ESPOFF] ; error code
332
mov [eax + TRPM.uActiveErrorCode], edx
333
mov dword [eax + TRPM.enmActiveType], TRPM_TRAP
334
mov edx, cr2 ;; @todo Check how expensive cr2 reads are!
335
mov dword [eax + TRPM.uActiveCR2], edx
338
; Check if we're in Hypervisor when this happend.
340
test dword [esp + CPUMCTXCORE.eflags], X86_EFL_VM
341
jnz short gt_NotHyperVisor
343
test byte [esp + 0ch + ESPOFF], 3h ; check CPL of the cs selector
344
jnz short gt_NotHyperVisor
348
; Trap in guest code.
351
%ifdef DEBUG_STUFF_TRPG
352
mov ebx, [esp + 4h + ESPOFF] ; error code
353
mov ecx, 'trpG' ; indicate trap.
354
mov edx, [esp + 0h + ESPOFF] ; vector number
356
call trpmDbgDumpRegisterFrame
360
; Do we have a GC handler for these traps?
362
mov edx, [esp + 0h + ESPOFF] ; vector number
363
mov eax, [g_apfnStaticTrapHandlersGuest + edx * 4]
365
jnz short gt_HaveHandler
366
mov eax, VINF_EM_RAW_GUEST_TRAP
367
jmp short gt_GuestTrap
370
; Call static handler.
373
push esp ; Param 2 - CPUMCTXCORE pointer.
374
push dword IMP(g_TRPM) ; Param 1 - Pointer to TRPM
376
add esp, byte 8 ; cleanup stack (cdecl)
378
je near gt_continue_guest
381
; Switch back to the host and process it there.
384
%ifdef VBOX_WITH_STATISTICS
385
mov edx, [esp + 0h + ESPOFF] ; vector number
386
imul edx, edx, byte STAMPROFILEADV_size ; assume < 128
388
add edx, TRPM.aStatGCTraps
389
STAM_PROFILE_ADV_STOP edx
392
call [edx + VM.pfnVMMGCGuestToHostAsmGuestCtx]
394
;; @todo r=bird: is this path actually every taken? if not we should replace this code with a panic.
397
; N.B. The stack has been changed now! No CPUMCTXCORE any longer. esp = vector number.
398
; N.B. Current scheduling design causes this code path to be unused.
399
; N.B. Better not use it when in V86 mode!
404
or eax, X86_CR0_WRITE_PROTECT
406
; Restore guest context and continue execution.
410
call NAME(CPUMGCRestoreInt)
411
lea esp, [esp + 0ch] ; cleanup call and skip vector & error code.
417
; Continue(/Resume/Restart/Whatever) guest execution.
421
%ifdef VBOX_WITH_STATISTICS
422
mov edx, [esp + 0h + ESPOFF] ; vector number
423
imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128
424
add edx, TRPM.aStatGCTraps
426
STAM_PROFILE_ADV_STOP edx
431
or eax, X86_CR0_WRITE_PROTECT
434
; restore guest state and start executing again.
435
test dword [esp + CPUMCTXCORE.eflags], X86_EFL_VM
438
mov ecx, [esp + CPUMCTXCORE.ecx]
439
mov edx, [esp + CPUMCTXCORE.edx]
440
mov ebx, [esp + CPUMCTXCORE.ebx]
441
mov ebp, [esp + CPUMCTXCORE.ebp]
442
mov esi, [esp + CPUMCTXCORE.esi]
443
mov edi, [esp + CPUMCTXCORE.edi]
445
mov eax, [esp + CPUMCTXCORE.esp]
446
mov [esp + 14h + ESPOFF], eax ; esp
447
mov eax, dword [esp + CPUMCTXCORE.ss]
448
mov [esp + 18h + ESPOFF], eax ; ss
450
mov eax, dword [esp + CPUMCTXCORE.gs]
451
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_GS
454
mov eax, dword [esp + CPUMCTXCORE.fs]
455
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_FS
458
mov eax, dword [esp + CPUMCTXCORE.es]
459
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_ES
462
mov eax, dword [esp + CPUMCTXCORE.ds]
463
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_DS
466
mov eax, dword [esp + CPUMCTXCORE.cs]
467
mov [esp + 0ch + ESPOFF], eax ; cs
468
mov eax, [esp + CPUMCTXCORE.eflags]
469
mov [esp + 10h + ESPOFF], eax ; eflags
470
mov eax, [esp + CPUMCTXCORE.eip]
471
mov [esp + 08h + ESPOFF], eax ; eip
473
; finally restore our scratch register eax
474
mov eax, [esp + CPUMCTXCORE.eax]
476
add esp, ESPOFF + 8 ; skip CPUMCTXCORE structure, error code and vector number
478
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_IRET
483
mov ecx, [esp + CPUMCTXCORE.ecx]
484
mov edx, [esp + CPUMCTXCORE.edx]
485
mov ebx, [esp + CPUMCTXCORE.ebx]
486
mov ebp, [esp + CPUMCTXCORE.ebp]
487
mov esi, [esp + CPUMCTXCORE.esi]
488
mov edi, [esp + CPUMCTXCORE.edi]
490
mov eax, [esp + CPUMCTXCORE.esp]
491
mov [esp + 14h + ESPOFF], eax ; esp
492
mov eax, dword [esp + CPUMCTXCORE.ss]
493
mov [esp + 18h + ESPOFF], eax ; ss
495
mov eax, dword [esp + CPUMCTXCORE.es]
496
mov [esp + 1ch + ESPOFF], eax ; es
497
mov eax, dword [esp + CPUMCTXCORE.ds]
498
mov [esp + 20h + ESPOFF], eax ; ds
499
mov eax, dword [esp + CPUMCTXCORE.fs]
500
mov [esp + 24h + ESPOFF], eax ; fs
501
mov eax, dword [esp + CPUMCTXCORE.gs]
502
mov [esp + 28h + ESPOFF], eax ; gs
504
mov eax, [esp + CPUMCTXCORE.eip]
505
mov [esp + 08h + ESPOFF], eax ; eip
506
mov eax, dword [esp + CPUMCTXCORE.cs]
507
mov [esp + 0ch + ESPOFF], eax ; cs
508
mov eax, [esp + CPUMCTXCORE.eflags]
509
mov [esp + 10h + ESPOFF], eax ; eflags
511
; finally restore our scratch register eax
512
mov eax, [esp + CPUMCTXCORE.eax]
514
add esp, ESPOFF + 8 ; skip CPUMCTXCORE structure, error code and vector number
516
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_IRET | TRPM_TRAP_IN_V86
520
; Trap in Hypervisor, try to handle it.
527
lea ebx, [esp + 14h + ESPOFF] ; calc esp at trap
528
mov [esp + CPUMCTXCORE.esp], ebx; update esp in register frame
529
mov [esp + CPUMCTXCORE.ss], ss ; update ss in register frame
531
; tell cpum about the context core.
532
xchg esi, eax ; save pTRPM - @todo reallocate this variable to esi, edi, or ebx
533
push esp ; Param 2 - The new CPUMCTXCORE pointer.
534
push IMP(g_VM) ; Param 1 - Pointer to the VM.
535
call NAME(CPUMHyperSetCtxCore)
536
add esp, byte 8 ; stack cleanup (cdecl)
537
xchg eax, esi ; restore pTRPM
539
; check for temporary handler.
540
movzx ebx, byte [eax + TRPM.uActiveVector]
542
xchg ecx, [eax + TRPM.aTmpTrapHandlers + ebx * 4] ; ecx = Temp handler pointer or 0
544
jnz short gt_Hyper_HaveTemporaryHandler
546
; check for static trap handler.
547
mov ecx, [g_apfnStaticTrapHandlersHyper + ebx * 4] ; ecx = Static handler pointer or 0
549
jnz short gt_Hyper_HaveStaticHandler
550
jmp gt_Hyper_AbandonShip
554
; Temporary trap handler present, call it (CDECL).
556
gt_Hyper_HaveTemporaryHandler:
557
push esp ; Param 2 - Pointer to CPUMCTXCORE.
558
push IMP(g_VM) ; Param 1 - Pointer to VM.
560
add esp, byte 8 ; cleanup stack (cdecl)
562
cmp eax, byte VINF_SUCCESS ; If completely handled Then resume execution.
563
je near gt_Hyper_Continue ; YASM BUG! YASMCHECK!
564
;; @todo Handle ALL returns types from temporary handlers!
565
jmp gt_Hyper_AbandonShip
569
; Static trap handler present, call it (CDECL).
571
gt_Hyper_HaveStaticHandler:
572
push esp ; Param 2 - Pointer to CPUMCTXCORE.
573
push eax ; Param 1 - Pointer to TRPM
575
add esp, byte 8 ; cleanup stack (cdecl)
577
cmp eax, byte VINF_SUCCESS ; If completely handled Then resume execution.
578
je short gt_Hyper_Continue
579
cmp eax, VINF_EM_DBG_HYPER_STEPPED
580
je short gt_Hyper_ToHost
581
cmp eax, VINF_EM_DBG_HYPER_BREAKPOINT
582
je short gt_Hyper_ToHost
583
cmp eax, VINF_EM_DBG_HYPER_ASSERTION
584
je short gt_Hyper_ToHost
585
jmp gt_Hyper_AbandonShip
588
; Pop back to the host to service the error.
593
call [edx + VM.pfnVMMGCGuestToHostAsm]
594
jmp short gt_Hyper_Continue
597
; Continue(/Resume/Restart/Whatever) hypervisor execution.
598
; Don't reset the TRPM state. Caller takes care of that.
603
mov ebx, [esp + 4h + ESPOFF] ; error code
604
mov ecx, 'resH' ; indicate trap.
605
mov edx, [esp + 0h + ESPOFF] ; vector number
607
call trpmDbgDumpRegisterFrame
609
; tell CPUM to use the default CPUMCTXCORE.
610
push byte 0 ; Param 2 - NULL indicating use default context core.
611
push IMP(g_VM) ; Param 1 - The VM pointer.
612
call NAME(CPUMHyperSetCtxCore)
613
add esp, byte 8 ; stack cleanup (cdecl)
615
%ifdef VBOX_WITH_STATISTICS
616
mov edx, [esp + 0h + ESPOFF] ; vector number
617
imul edx, edx, byte STAMPROFILEADV_size ; assumes < 128
618
add edx, TRPM.aStatGCTraps
620
STAM_PROFILE_ADV_STOP edx
624
mov ecx, [esp + CPUMCTXCORE.ecx]
625
mov edx, [esp + CPUMCTXCORE.edx]
626
mov ebx, [esp + CPUMCTXCORE.ebx]
627
mov ebp, [esp + CPUMCTXCORE.ebp]
628
mov esi, [esp + CPUMCTXCORE.esi]
629
mov edi, [esp + CPUMCTXCORE.edi]
631
mov eax, dword [esp + CPUMCTXCORE.gs]
632
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_GS | TRPM_TRAP_IN_HYPER
635
mov eax, dword [esp + CPUMCTXCORE.fs]
636
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_FS | TRPM_TRAP_IN_HYPER
639
mov eax, dword [esp + CPUMCTXCORE.es]
641
mov eax, dword [esp + CPUMCTXCORE.ds]
646
mov eax, [esp + CPUMCTXCORE.eip]
647
mov [esp + 08h + ESPOFF], eax ; eip
648
mov eax, dword [esp + CPUMCTXCORE.cs]
649
mov [esp + 0ch + ESPOFF], eax ; cs
650
mov eax, [esp + CPUMCTXCORE.eflags]
651
mov [esp + 10h + ESPOFF], eax ; eflags
653
; finally restore our scratch register eax
654
mov eax, [esp + CPUMCTXCORE.eax]
656
add esp, ESPOFF + 8 ; skip CPUMCTXCORE structure, error code and vector number
662
; ABANDON SHIP! DON'T PANIC!
664
gt_Hyper_AbandonShip:
666
mov ebx, [esp + 4h + ESPOFF] ; error code
667
mov ecx, 'trpH' ; indicate trap.
668
mov edx, [esp + 0h + ESPOFF] ; vector number
670
call trpmDbgDumpRegisterFrame
676
mov eax, VERR_TRPM_DONT_PANIC
677
call [edx + VM.pfnVMMGCGuestToHostAsmHyperCtx]
681
jmp gt_Hyper_DontPanic ; this shall never ever happen!
683
ENDPROC TRPMGCHandlerGeneric
690
; We start by 256 push <vector no.> + jmp interruptworker
693
BEGINPROC_EXPORTED TRPMGCHandlerInterupt
694
; NASM has some nice features, here an example of a loop.
697
db 06ah, i ; push imm8 - note that this is a signextended value.
698
jmp ti_GenericInterrupt
704
; Main interrupt handler for the guest context
716
; ESP -> 0 Vector number (only use low byte!).
723
; Setup CPUMCTXCORE frame
725
; ASSUMPTION: If trap in hypervisor, we assume that we can read two dword
726
; under the bottom of the stack. This is atm safe.
727
; ASSUMPTION: There is sufficient stack space.
728
; ASSUMPTION: The stack is not write protected.
730
%define ESPOFF CPUMCTXCORE_size
732
sub esp, CPUMCTXCORE_size
733
mov [esp + CPUMCTXCORE.eax], eax
734
mov [esp + CPUMCTXCORE.ecx], ecx
735
mov [esp + CPUMCTXCORE.edx], edx
736
mov [esp + CPUMCTXCORE.ebx], ebx
737
mov [esp + CPUMCTXCORE.esi], esi
738
mov [esp + CPUMCTXCORE.edi], edi
739
mov [esp + CPUMCTXCORE.ebp], ebp
741
mov eax, [esp + 04h + ESPOFF] ; eip
742
mov [esp + CPUMCTXCORE.eip], eax
743
mov eax, dword [esp + 08h + ESPOFF] ; cs
744
mov [esp + CPUMCTXCORE.cs], eax
745
mov eax, [esp + 0ch + ESPOFF] ; eflags
746
mov [esp + CPUMCTXCORE.eflags], eax
748
mov eax, [esp + 10h + ESPOFF] ; esp
749
mov [esp + CPUMCTXCORE.esp], eax
750
mov eax, dword [esp + 14h + ESPOFF] ; ss
751
mov [esp + CPUMCTXCORE.ss], eax
754
mov dword [esp + CPUMCTXCORE.es], eax
756
mov dword [esp + CPUMCTXCORE.ds], eax
758
mov dword [esp + CPUMCTXCORE.fs], eax
760
mov dword [esp + CPUMCTXCORE.gs], eax
762
test dword [esp + CPUMCTXCORE.eflags], X86_EFL_VM
763
jz short ti_SkipV86Entry
766
; The DS, ES, FS and GS registers are zeroed in V86 mode and their real values are on the stack
768
mov eax, dword [esp + ESPOFF + 18h]
769
mov dword [esp + CPUMCTXCORE.es], eax
771
mov eax, dword [esp + ESPOFF + 1Ch]
772
mov dword [esp + CPUMCTXCORE.ds], eax
774
mov eax, dword [esp + ESPOFF + 20h]
775
mov dword [esp + CPUMCTXCORE.fs], eax
777
mov eax, dword [esp + ESPOFF + 24h]
778
mov dword [esp + CPUMCTXCORE.gs], eax
786
and eax, ~X86_CR0_WRITE_PROTECT
790
; Load Hypervisor DS and ES (get it from the SS)
797
; Store the information about the active trap/interrupt.
800
movzx edx, byte [esp + 0h + ESPOFF] ; vector number
801
mov [eax + TRPM.uActiveVector], edx
803
mov dword [eax + TRPM.enmActiveType], TRPM_HARDWARE_INT
805
mov [eax + TRPM.uActiveErrorCode], edx
806
mov [eax + TRPM.uActiveCR2], edx
809
; Check if we're in Hypervisor when this happend.
811
test byte [esp + 08h + ESPOFF], 3h ; check CPL of the cs selector
812
jnz short gi_NotHyperVisor
816
; Trap in guest code.
819
and dword [esp + CPUMCTXCORE.eflags], ~010000h ; Clear RF (Resume Flag). @todo make %defines for eflags.
820
; The guest shall not see this in it's state.
821
%ifdef DEBUG_STUFF_INT
822
mov ecx, 'intG' ; indicate trap.
823
movzx edx, byte [esp + 0h + ESPOFF] ; vector number
825
call trpmDbgDumpRegisterFrame
829
; Switch back to the host and process it there.
832
mov eax, VINF_EM_RAW_INTERRUPT
833
call [edx + VM.pfnVMMGCGuestToHostAsmGuestCtx]
837
; NOTE that the stack has been changed now!
838
; there is no longer any CPUMCTXCORE around and esp points to vector number!
843
dec edx ; edx = 0ffffffffh
844
xchg [eax + TRPM.uActiveVector], edx
845
mov [eax + TRPM.uPrevVector], edx
849
or eax, X86_CR0_WRITE_PROTECT
851
; restore guest context and continue execution.
854
call NAME(CPUMGCRestoreInt)
855
lea esp, [esp + 0ch] ; cleanup call and skip vector & error code.
859
; -+- Entry point -+-
861
; We're in hypervisor mode which means no guest context
862
; and special care to be taken to restore the hypervisor
863
; context correctely.
865
; ATM the only place this can happen is when entering a trap handler.
866
; We make ASSUMPTIONS about this in respects to the WP CR0 bit
869
lea eax, [esp + 14h + ESPOFF] ; calc esp at trap
870
mov [esp + CPUMCTXCORE.esp], eax ; update esp in register frame
871
mov [esp + CPUMCTXCORE.ss], ss ; update ss in register frame
873
%ifdef DEBUG_STUFF_INT
874
mov ebx, [esp + 4h + ESPOFF] ; error code
875
mov ecx, 'intH' ; indicate hypervisor interrupt.
876
movzx edx, byte [esp + 0h + ESPOFF] ; vector number
878
call trpmDbgDumpRegisterFrame
883
mov eax, VINF_EM_RAW_INTERRUPT_HYPER
884
call [edx + VM.pfnVMMGCGuestToHostAsm]
885
%ifdef DEBUG_STUFF_INT
892
; Reset TRPM state - don't record this.
894
mov dword [eax + TRPM.uActiveVector], 0ffffffffh
897
; Restore the hypervisor context and return.
899
mov ecx, [esp + CPUMCTXCORE.ecx]
900
mov edx, [esp + CPUMCTXCORE.edx]
901
mov ebx, [esp + CPUMCTXCORE.ebx]
902
mov ebp, [esp + CPUMCTXCORE.ebp]
903
mov esi, [esp + CPUMCTXCORE.esi]
904
mov edi, [esp + CPUMCTXCORE.edi]
906
; In V86 mode DS, ES, FS & GS are restored by the iret
907
test dword [esp + CPUMCTXCORE.eflags], X86_EFL_VM
908
jnz short ti_SkipSelRegs
910
mov eax, [esp + CPUMCTXCORE.gs]
911
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_GS | TRPM_TRAP_IN_HYPER
914
mov eax, [esp + CPUMCTXCORE.fs]
915
TRPM_NP_GP_HANDLER NAME(trpmGCTrapInGeneric), TRPM_TRAP_IN_MOV_FS | TRPM_TRAP_IN_HYPER
918
mov eax, [esp + CPUMCTXCORE.es]
920
mov eax, [esp + CPUMCTXCORE.ds]
924
; finally restore our scratch register eax
925
mov eax, [esp + CPUMCTXCORE.eax]
927
; skip esp, ss, cs, eip & eflags. Done by iret
929
add esp, ESPOFF + 4h ; skip CPUMCTXCORE structure & vector number.
933
ENDPROC TRPMGCHandlerInterupt
938
; Trap handler for #MC
940
; This handler will forward the #MC to the host OS. Since this
941
; is generalized in the generic interrupt handler, we just disable
942
; interrupts and push vector number and jump to the generic code.
945
; 10 SS (only if ring transition.)
946
; c ESP (only if ring transition.)
954
BEGINPROC_EXPORTED TRPMGCHandlerTrap12
957
jmp ti_GenericInterrupt
958
ENDPROC TRPMGCHandlerTrap12
964
; Trap handler for double fault (#DF).
966
; This is a special trap handler executes in separate task with own TSS, with
967
; one of the intermediate memory contexts instead of the shadow context.
968
; The handler will unconditionally print an report to the comport configured
969
; for the COM_S_* macros before attempting to return to the host. If it it ends
970
; up double faulting more than 10 times, it will simply cause an tripple fault
971
; to get us out of the mess.
973
; @param esp Half way down the hypvervisor stack + the trap frame.
974
; @param ebp Half way down the hypvervisor stack.
975
; @param eflags Interrupts disabled, nested flag is probably set (we don't care).
976
; @param ecx The address of the hypervisor TSS.
977
; @param edi Same as ecx.
978
; @param eax Same as ecx.
979
; @param edx Address of the VM structure.
980
; @param esi Same as edx.
981
; @param ebx Same as edx.
982
; @param ss Hypervisor DS.
983
; @param ds Hypervisor DS.
984
; @param es Hypervisor DS.
989
; @remark To be able to catch errors with WP turned off, it is required that the
990
; TSS GDT descriptor and the TSSes are writable (X86_PTE_RW). See SELM.cpp
991
; for how to enable this.
993
; @remark It is *not* safe to resume the VMM after a double fault. (At least not
994
; without clearing the busy flag of the TssTrap8 and fixing whatever cause it.)
997
BEGINPROC_EXPORTED TRPMGCHandlerTrap08
998
cli ; slight paranoia
1002
; Load Hypervisor DS and ES (get it from the SS) - paranoia, but the TSS could be overwritten.. :)
1008
COM_S_PRINT 10,13,'*** Guru Mediation 00000008 - Double Fault! ***',10,13
1011
; Disable write protection.
1014
and eax, ~X86_CR0_WRITE_PROTECT
1020
COM_S_PRINT ' prevTSS='
1022
COM_S_PRINT ' prevCR3='
1023
mov eax, [ecx + VBOXTSS.cr3]
1025
COM_S_PRINT ' prevLdtr='
1026
movzx eax, word [ecx + VBOXTSS.selLdt]
1031
; Create CPUMCTXCORE structure.
1033
sub esp, CPUMCTXCORE_size
1035
mov eax, [ecx + VBOXTSS.eip]
1036
mov [esp + CPUMCTXCORE.eip], eax
1037
mov eax, [ecx + VBOXTSS.eflags]
1038
mov [esp + CPUMCTXCORE.eflags], eax
1040
movzx eax, word [ecx + VBOXTSS.cs]
1041
mov dword [esp + CPUMCTXCORE.cs], eax
1042
movzx eax, word [ecx + VBOXTSS.ds]
1043
mov dword [esp + CPUMCTXCORE.ds], eax
1044
movzx eax, word [ecx + VBOXTSS.es]
1045
mov dword [esp + CPUMCTXCORE.es], eax
1046
movzx eax, word [ecx + VBOXTSS.fs]
1047
mov dword [esp + CPUMCTXCORE.fs], eax
1048
movzx eax, word [ecx + VBOXTSS.gs]
1049
mov dword [esp + CPUMCTXCORE.gs], eax
1050
movzx eax, word [ecx + VBOXTSS.ss]
1051
mov [esp + CPUMCTXCORE.ss], eax
1052
mov eax, [ecx + VBOXTSS.esp]
1053
mov [esp + CPUMCTXCORE.esp], eax
1054
mov eax, [ecx + VBOXTSS.ecx]
1055
mov [esp + CPUMCTXCORE.ecx], eax
1056
mov eax, [ecx + VBOXTSS.edx]
1057
mov [esp + CPUMCTXCORE.edx], eax
1058
mov eax, [ecx + VBOXTSS.ebx]
1059
mov [esp + CPUMCTXCORE.ebx], eax
1060
mov eax, [ecx + VBOXTSS.eax]
1061
mov [esp + CPUMCTXCORE.eax], eax
1062
mov eax, [ecx + VBOXTSS.ebp]
1063
mov [esp + CPUMCTXCORE.ebp], eax
1064
mov eax, [ecx + VBOXTSS.esi]
1065
mov [esp + CPUMCTXCORE.esi], eax
1066
mov eax, [ecx + VBOXTSS.edi]
1067
mov [esp + CPUMCTXCORE.edi], eax
1073
mov ecx, 'trpH' ; indicate trap.
1074
mov edx, 08h ; vector number
1076
call trpmDbgDumpRegisterFrame
1079
; Should we try go back?
1081
inc dword [df_Count]
1082
cmp dword [df_Count], byte 10
1084
jmp df_tripple_fault
1088
; Try return to the host.
1091
COM_S_PRINT 'Trying to return to host...',10,13
1094
mov eax, VERR_TRPM_PANIC
1095
call [edx + VM.pfnVMMGCGuestToHostAsmHyperCtx]
1096
jmp short df_to_host
1099
; Perform a tripple fault.
1102
COM_S_PRINT 'Giving up - tripple faulting the machine...',10,13
1110
jmp df_tripple_fault
1112
ENDPROC TRPMGCHandlerTrap08
1118
; Internal procedure used to dump registers.
1120
; @param eax Pointer to CPUMCTXCORE.
1121
; @param edx Vector number
1122
; @param ecx 'trap' if trap, 'int' if interrupt.
1123
; @param ebx Error code if trap.
1125
trpmDbgDumpRegisterFrame:
1126
sub esp, byte 8 ; working space for sidt/sgdt/etc
1128
; Init _must_ be done on host before crashing!
1145
COM_S_PRINT 10,13,'*** Bogus Dump Code '
1148
%if 1 ; the verbose version
1151
COM_S_PRINT 10,13,'*** Interrupt (Guest) '
1156
COM_S_PRINT 10,13,'*** Interrupt (Hypervisor) '
1161
COM_S_PRINT 10,13,'*** Trap '
1164
%else ; the short version
1178
%endif ; the short version
1181
COM_S_PRINT 10,13,'*** Guru Meditation '
1185
COM_S_PRINT 10,13,'*** Resuming Hypervisor Trap '
1190
COM_S_PRINT ' ErrorCode='
1197
COM_S_PRINT ' ***',10,13,'cs:eip='
1198
movzx ecx, word [eax + CPUMCTXCORE.cs]
1201
mov ecx, [eax + CPUMCTXCORE.eip]
1204
COM_S_PRINT ' ss:esp='
1205
movzx ecx, word [eax + CPUMCTXCORE.ss]
1208
mov ecx, [eax + CPUMCTXCORE.esp]
1213
COM_S_PRINT 10,13,' gdtr='
1214
movzx ecx, word [esp]
1221
COM_S_PRINT ' idtr='
1222
movzx ecx, word [esp]
1229
str [esp] ; yasm BUG! it generates sldt [esp] here! YASMCHECK!
1230
COM_S_PRINT 10,13,' tr='
1231
movzx ecx, word [esp]
1235
COM_S_PRINT ' ldtr='
1236
movzx ecx, word [esp]
1239
COM_S_PRINT ' eflags='
1240
mov ecx, [eax + CPUMCTXCORE.eflags]
1244
COM_S_PRINT 10,13,'cr0='
1260
COM_S_PRINT 10,13,' ds='
1261
movzx ecx, word [eax + CPUMCTXCORE.ds]
1265
movzx ecx, word [eax + CPUMCTXCORE.es]
1269
movzx ecx, word [eax + CPUMCTXCORE.fs]
1273
movzx ecx, word [eax + CPUMCTXCORE.gs]
1277
COM_S_PRINT 10,13,'eax='
1278
mov ecx, [eax + CPUMCTXCORE.eax]
1282
mov ecx, [eax + CPUMCTXCORE.ebx]
1286
mov ecx, [eax + CPUMCTXCORE.ecx]
1290
mov ecx, [eax + CPUMCTXCORE.edx]
1294
COM_S_PRINT 10,13,'esi='
1295
mov ecx, [eax + CPUMCTXCORE.esi]
1299
mov ecx, [eax + CPUMCTXCORE.edi]
1303
mov ecx, [eax + CPUMCTXCORE.ebp]